ThunderPhone 2.0 yayında.Kendi başınıza kullanmaya başlayın; dakikada 2¢'den 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 çağrısı, atanmış bir ajanı olmayan bir numaraya ulaştığında veya mode="webhook" ayarındaki yayınlanabilir anahtarda bir web bileşeni oturumu başladığında ThunderPhone, eski webhook URL'nize bloklayıcı bir telephony.incoming / web.incoming isteği gönderir ve yapılandırma yanıtı için en fazla 10 saniye bekler. Her çağrı için istemi, sesi ve araçları dinamik olarak seçmek üzere bu alışverişi kullanın — uçtan uca örüntü için dinamik çağrı yapılandırma rehberine bakın.

Bloklayıcı alışverişin geri dönüş seçeneği yoktur: işleyiciniz 2xx olmayan bir durum döndürürse, zaman aşımına uğrarsa veya doğrulaması başarısız olan bir yapılandırma döndürürse çağrı reddedilir (telefon çağrısı bağlanmaz; bileşen oturumu isteği 502/422 ile başarısız olur). Hızlı yanıt verin — siz karar verirken arayan kişi çalma sesini duyar.

İ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_idintegerÇağrı kimliği
origin_domainstringBileşeni barındıran sayfa kaynağı
publishable_key_prefixstringOturumu açan yayınlanabilir anahtarın ilk karakterleri
language, primary_languagestringBileşen oturumu bir dil geçersiz kılma ayarı istediğinde bulunur
voicestringBileşen oturumu bir ses geçersiz kılma ayarı istediğinde bulunur
website_contextstringBileşen, oturum başına sayfa bağlamı ilettiğinde bulunur

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
promptstringevetYapay zeka ajanını yönlendiren sistem istemi
voicestringevetGET /v1/voices içinden ses kimliği; örneğin john. voice_name bir takma ad olarak kabul edilir. Bilinmeyen sesler doğrulamadan geçemez ve çağrıyı reddeder
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 ekler; küçük bir gecikme/maliyet artışı karşılığında düzeltmeleri ve yazım/numara ağırlıklı veri toplamayı iyileştirir. 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_languagesstring dizisihayırAjanın geçebileceğ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)
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 öncesindeki arayan sessizliği 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
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ı
toolsdizihayırSatır içi işlev aracı şemaları (Function Tools bölümüne bakın)
call_idintegerhayırİsteğin çağrı kimliğinin isteğe bağlı yankısı; yoksayılır

prompt ve voice zorunlu olduğundan, {} döndürmek veya doğrulamadan geçemeyen herhangi bir yanıt çağrıyı 422 ile reddeder — 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