ThunderPhone 2.0 अब लाइव है।सेल्फ़-सर्व, 2¢/मिनट से।घोषणा पढ़ें

Webhooks

telephony.incoming / web.incoming

ब्लॉकिंग वेबहुक जो रियल टाइम में इनबाउंड कॉल के कॉन्फ़िगरेशन को आकार देता है।

जब कोई इनबाउंड फोन कॉल बिना असाइन किए गए एजेंट वाले नंबर पर पहुंचती है, या वेब विजेट सेशन mode="webhook" में किसी पब्लिशेबल की पर शुरू होता है, तो ThunderPhone आपके लीगेसी वेबहुक URL को एक ब्लॉकिंग telephony.incoming / web.incoming रिक्वेस्ट भेजता है और कॉन्फ़िगरेशन रिस्पॉन्स की प्रतीक्षा करता है: फोन कॉल के लिए अधिकतम 13 सेकंड, जिसमें एक रीट्राई शामिल है, और विजेट सेशन के लिए अधिकतम 10 सेकंड (टाइमआउट और रीट्राई देखें)। हर कॉल के लिए प्रॉम्प्ट, वॉइस, और टूल्स को डायनामिक रूप से चुनने के लिए इस एक्सचेंज का उपयोग करें — एंड-टू-एंड पैटर्न के लिए डायनामिक कॉल कॉन्फ़िगरेशन गाइड देखें।

टाइमआउट और रिट्राइ

जल्दी जवाब दें: आपके निर्णय लेने के दौरान कॉलर लाइन पर इंतज़ार कर रहा है।

फोन कॉल (telephony.incoming) के लिए:

  • पहले प्रयास में 10 सेकंड तक लग सकते हैं।
  • अगर टाइमआउट होता है, कनेक्ट नहीं हो पाता, या 5xx, 408 या 429 रिस्पॉन्स मिलता है, तो ThunderPhone एक बार फिर कोशिश करता है। रिट्राइ को पूरे एक्सचेंज के लिए 13-सेकंड के बजट में बचा हुआ समय मिलता है: टाइमआउट हुए पहले प्रयास के बाद लगभग 3 सेकंड, तेज़ विफलता के बाद लगभग पूरे 13 सेकंड। अगर 2 सेकंड से कम समय बचता है, तो रिट्राइ नहीं किया जाता।
  • कोई भी अन्य 4xx रिस्पॉन्स, साइज़ सीमा से बड़ा रिस्पॉन्स, या ऐसा 2xx जिसका बॉडी मान्य कॉन्फ़िगरेशन नहीं है, अंतिम माना जाता है और उस पर रिट्राइ नहीं होता।
  • दोनों प्रयास एक ही बॉडी, एक ही X-ThunderPhone-Signature, और एक ही X-ThunderPhone-Idempotency-Key हेडर (telephony-incoming-<call_id>) भेजते हैं, इसलिए साइड इफेक्ट्स वाला हैंडलर रिट्राइ को पहचान सकता है।

कोई फॉलबैक एजेंट नहीं है। अगर उपयोग योग्य कॉन्फ़िगरेशन नहीं मिलता, तो कॉलर को साइलेंट लाइन पर छोड़ने के बजाय कॉल तुरंत समाप्त कर दी जाती है। यह कॉल हिस्ट्री में end_reason inbound_config_webhook_failed के साथ एक असफल, बिना बिल वाली कॉल के रूप में दिखाई देती है, और सामान्य telephony.complete इवेंट भेजा जाता है।

विजेट सेशन (web.incoming) को 10 सेकंड तक का केवल एक प्रयास मिलता है। अगर यह विफल होता है, तो सेशन रिक्वेस्ट 502 या 422 के साथ विफल होती है।

रिक्वेस्ट पेलोड

फ़ोन कॉल (telephony.incoming) के लिए:

{
  "type": "telephony.incoming",
  "data": {
    "call_id":     987654321,
    "from_number": "+14155550199",
    "to_number":   "+15551234567"
  }
}
फ़ील्डटाइपविवरण
call_idintegerकॉल id — इस कॉल के सभी इवेंट्स में स्थिर
from_numberstringE.164 कॉलर नंबर
to_numberstringE.164 डेस्टिनेशन (आपके ThunderPhone नंबरों में से एक)

वेब विजेट सेशन (web.incoming) के लिए, data फ़ोन नंबरों के बजाय एम्बेडिंग पेज की पहचान करता है:

{
  "type": "web.incoming",
  "data": {
    "call_id": 987654322,
    "origin_domain": "https://example.com",
    "publishable_key_prefix": "pk_live_a1b2"
  }
}
फ़ील्डटाइपविवरण
call_idइंटीजरकॉल आईडी
origin_domainस्ट्रिंगविजेट होस्ट करने वाले पेज का ओरिजिन, जैसा ब्राउज़र ने भेजा है। कोई नॉन-ब्राउज़र क्लाइंट कोई भी वैल्यू भेज सकता है, इसलिए इसे इस बात के प्रमाण के रूप में न मानें कि रिक्वेस्ट कहाँ से आई है
publishable_key_prefixस्ट्रिंगसेशन खोलने वाली publishable key के शुरुआती कैरेक्टर
language, primary_languageस्ट्रिंगविजेट सेशन द्वारा भाषा ओवरराइड का अनुरोध करने पर मौजूद होता है
voiceस्ट्रिंगविजेट सेशन द्वारा वॉइस ओवरराइड का अनुरोध करने पर मौजूद होता है
website_contextस्ट्रिंगविजेट द्वारा प्रति-सेशन पेज कॉन्टेक्स्ट भेजने पर मौजूद होता है

ओवरराइड फ़ील्ड (language, voice, website_context, और कोई भी ब्राउज़र variables) केवल तब आते हैं जब publishable key उन्हें अपने ब्राउज़र ओवरराइड्स में अनुमति देती है। ऐसा सेशन रिक्वेस्ट जिसमें ऐसी कोई फ़ील्ड हो जिसकी key अनुमति नहीं देती, इस webhook के कॉल होने से पहले अस्वीकार कर दिया जाता है।


रिस्पॉन्स स्कीमा

इस कॉल के लिए एजेंट कॉन्फ़िगरेशन का वर्णन करने वाला JSON ऑब्जेक्ट लौटाएँ। prompt और voice आवश्यक हैं; बाकी सब वैकल्पिक है।

{
  "prompt":  "You are a helpful booking assistant for Acme Restaurant.",
  "voice":   "john",
  "product": "spark",
  "background_track": null,
  "tools":   []
}
फ़ील्डप्रकारआवश्यकविवरण
promptस्ट्रिंगहाँएजेंट को संचालित करने वाला सिस्टम प्रॉम्प्ट
voiceस्ट्रिंगहाँGET /v1/voices से वॉइस आईडी, उदाहरण के लिए john। voice_name को उपनाम के रूप में स्वीकार किया जाता है। अज्ञात वॉइस वेलिडेशन में विफल होती हैं और कॉल अस्वीकार कर देती हैं
productस्ट्रिंगनहींडिफ़ॉल्ट रूप से spark। अनुमत: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack
thinking_levelस्ट्रिंगनहींminimal, base (डिफ़ॉल्ट), या extra। Storm उत्पादों के लिए ओवरराइड किया जाता है: storm-extra* extra को बाध्य करता है, अन्य storm-* base को बाध्य करते हैं
audio_context_modeस्ट्रिंगनहींfull (डिफ़ॉल्ट) या reduced
watchdog_enabledबूलियननहींइस कॉल के लिए सुपरविजन सक्षम करें। डिफ़ॉल्ट false
additional_audio_contextबूलियन | nullनहींकेवल सबसे हालिया टर्न के बजाय कॉलर ऑडियो के पिछले कुछ टर्न शामिल करें, जिससे कम लेटेंसी/लागत ओवरहेड पर सुधार और वर्तनी/संख्या-प्रधान डेटा कलेक्शन बेहतर होता है। इनबाउंड सेशनों के लिए डिफ़ॉल्ट रूप से चालू और आउटबाउंड फ़ोन कॉल के लिए बंद; null डिफ़ॉल्ट बनाए रखता है
storm_feedback_modeस्ट्रिंगनहींnone, acknowledgement (डिफ़ॉल्ट), या tick
languageस्ट्रिंगनहींprimary_language का संक्षिप्त रूप
primary_languageस्ट्रिंगनहींभाषा कोड, नॉर्मलाइज़्ड (डिफ़ॉल्ट en)। जिन कोड का समाधान नहीं हो सकता, वे कॉल अस्वीकार कर देते हैं
has_additional_languagesबूलियननहींडिफ़ॉल्ट false
additional_languagesस्ट्रिंग की ऐरेनहींअतिरिक्त भाषाएँ जिनमें एजेंट स्विच कर सकता है
native_voice_switchingबूलियननहींडिफ़ॉल्ट false। जब कॉल किसी अन्य भाषा में स्विच होती है, तो कॉन्फ़िगर की गई वॉइस रखने के बजाय उस भाषा की मूल वॉइस पर स्विच करें (लिंग के अनुसार मिलान किया गया)
language_switchingस्ट्रिंग | nullनहींask_first (डिफ़ॉल्ट) या follow_caller; null, ask_first के समान है। बहुभाषी एजेंट के लिए यह निर्धारित करता है कि दूसरा व्यक्ति उसकी किसी अन्य भाषा में बोले तो कैसे संभालना है। ask_first भाषा का अनुरोध करने या उसमें पूरा वाक्य बोलने पर तुरंत स्विच करता है, और “हाँ” जैसी छोटी बात के बाद पूछता है कि क्या उसी भाषा में जारी रखना है। follow_caller उनके द्वारा बोली गई किसी भी कॉन्फ़िगर की गई भाषा में स्विच करता है, भले ही वे केवल एक शब्द बोलें। केवल तब लागू होता है जब additional_languages सेट हो
background_trackस्ट्रिंग | nullनहींएम्बिएंट ऑडियो आईडी या null
acknowledgement_prompt_modeस्ट्रिंगनहींauto (डिफ़ॉल्ट) या manual (Storm-with-ack उत्पाद)
acknowledgement_promptस्ट्रिंगनहींacknowledgement_prompt_mode="manual" होने पर उपयोग किया जाता है
silence_interval_secondsइंटीजर | nullनहीं5–120। चेक-इन से पहले कॉलर की चुप्पी के सेकंड
silence_max_checkinsइंटीजर | nullनहीं1–10
silence_checkins_enabledबूलियननहींडिफ़ॉल्ट true
connect_tone_enabledबूलियननहींडिफ़ॉल्ट false
pronunciation_dictsबूलियन | nullनहींडिफ़ॉल्ट false; null, false के समान है। true होने पर, कॉल का Cartesia स्पीच कॉल की भाषा के लिए ThunderPhone की उच्चारण डिक्शनरी का उपयोग करता है, जहाँ उपलब्ध हो। फ़ोन और विजेट कॉल के लिए काम करता है। केवल ThunderPhone की अपनी Cartesia वॉइस पर लागू होता है, आपके स्वयं के Cartesia API key की वॉइस पर नहीं। agent_id के साथ उपयोग नहीं होता, जहाँ सेव किए गए एजेंट की सेटिंग्स लागू होती हैं
voicemail_actionस्ट्रिंगनहींprompt (डिफ़ॉल्ट), hangup, या message
voicemail_messageस्ट्रिंगनहींvoicemail_action="message" होने पर उपयोग किया जाता है
agent_nameस्ट्रिंगनहींडैशबोर्ड्स और विजेट में रिपोर्ट किया गया डिस्प्ले नाम
org_nameस्ट्रिंगनहींएजेंट के पर्सोना के लिए संगठन का डिस्प्ले नाम
toolsऐरेनहींइनलाइन फ़ंक्शन-टूल स्कीमा (Function Tools देखें)
transfer_destinationsऑब्जेक्ट की ऐरे | nullनहींइस कॉल को ट्रांसफ़र किए जा सकने वाले अधिकतम 50 {name, number} एंट्री, जिन्हें एजेंट के ट्रांसफ़र नंबरों की तरह वेलिडेट किया जाता है। एजेंट नाम से और केवल इन्हीं पर ट्रांसफ़र करता है; [] का अर्थ है कोई ट्रांसफ़र नहीं। एजेंट को अपने चुने नंबर पर ट्रांसफ़र करने देने के लिए इसे छोड़ दें या null भेजें
timezoneस्ट्रिंगनहींइस कॉल के लिए IANA टाइम ज़ोन, जैसे America/Chicago। एजेंट अपनी स्वयं की टाइम ज़ोन के बजाय इसमें तारीख और समय बताता है। agent_id के साथ भी अनुमत है। जो मान IANA ज़ोन नहीं हैं, उन्हें अनदेखा किया जाता है। हर कॉल के लिए टाइम ज़ोन सेट करें देखें
call_idइंटीजरनहींअनुरोध की कॉल आईडी का वैकल्पिक इको; अनदेखा किया जाता है

क्योंकि prompt और voice आवश्यक हैं, {} या वेलिडेशन में विफल कोई भी रिस्पॉन्स लौटाने पर कॉल अस्वीकार हो जाती है: फोन कॉल टाइमआउट और रिट्राई में बताए अनुसार समाप्त हो जाती है, और विजेट सेशन अनुरोध 422 के साथ विफल होता है। इस पाथ पर कोई स्टैटिक-एजेंट फॉलबैक नहीं है (वेबहुक मोड में किसी नंबर या की के लिए कोई एजेंट असाइन नहीं होता)।


रिस्पॉन्स आकार सीमा


उदाहरण हैंडलर

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({});
  },
);

फंक्शन टूल्स के साथ रिस्पॉन्स

टूल्स अटैच करें ताकि AI बातचीत के बीच में आपके API को कॉल कर सके:

{
  "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"
        }
      }
    }
  ]
}

प्रोडक्ट टियर चीट शीट

प्रोडक्टलेटेंसीरीजनिंगस्वीकृति
sparkसबसे कमबेसिक—
boltकमबेहतर—
storm-baseमध्यममजबूत—
storm-base-with-ackमध्यममजबूतसोचते समय ऑटो फिलर
storm-extraअधिकगहन—
storm-extra-with-ackअधिकगहनसोचते समय ऑटो फिलर

संबंधित