telephony.incoming / web.incoming
ब्लॉकिंग वेबहुक जो रियल टाइम में इनबाउंड कॉल के कॉन्फ़िगरेशन को आकार देता है।
जब किसी इनबाउंड फ़ोन कॉल का नंबर बिना असाइन किए गए
एजेंट के होता है, या किसी publishable key पर
mode="webhook" में वेब विजेट सेशन शुरू होता है, तो ThunderPhone आपके
लेगेसी वेबहुक URL
पर एक ब्लॉकिंग
telephony.incoming / web.incoming रिक्वेस्ट भेजता है और कॉन्फ़िगरेशन
रिस्पॉन्स के लिए 10 सेकंड तक प्रतीक्षा करता है। हर कॉल के लिए प्रॉम्प्ट,
वॉइस और टूल्स को डायनामिक रूप से चुनने के लिए इस एक्सचेंज का उपयोग करें —
पूरे पैटर्न के लिए डायनामिक कॉल कॉन्फ़िगरेशन गाइड
देखें।
इस ब्लॉकिंग एक्सचेंज का कोई फ़ॉलबैक नहीं है: यदि आपका हैंडलर non-2xx
स्टेटस लौटाता है, टाइम आउट होता है, या ऐसा कॉन्फ़िग लौटाता है जो वैलिडेशन
में विफल हो जाता है, तो कॉल अस्वीकार कर दी जाती है (फ़ोन कॉल कनेक्ट नहीं
होती; विजेट सेशन रिक्वेस्ट 502/422 के साथ विफल होती है)। तुरंत जवाब
दें — जब आप निर्णय ले रहे होते हैं, तब कॉलर रिंगबैक सुन रहा होता है।
रिक्वेस्ट पेलोड
फ़ोन कॉल (telephony.incoming) के लिए:
{
"type": "telephony.incoming",
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}| फ़ील्ड | टाइप | विवरण |
|---|---|---|
call_id | integer | कॉल id — इस कॉल के सभी इवेंट्स में स्थिर |
from_number | string | E.164 कॉलर नंबर |
to_number | string | E.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 | integer | कॉल id |
origin_domain | string | विजेट होस्ट करने वाले पेज का ओरिजिन |
publishable_key_prefix | string | सेशन खोलने वाली publishable key के शुरुआती कैरेक्टर |
language, primary_language | string | जब विजेट सेशन ने भाषा ओवरराइड का अनुरोध किया हो, तब मौजूद |
voice | string | जब विजेट सेशन ने वॉइस ओवरराइड का अनुरोध किया हो, तब मौजूद |
website_context | string | जब विजेट ने प्रति-सेशन पेज कॉन्टेक्स्ट पास किया हो, तब मौजूद |
रिस्पॉन्स स्कीमा
इस कॉल के लिए एजेंट कॉन्फ़िगरेशन का वर्णन करने वाला 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। जब कॉल किसी अन्य भाषा पर स्विच होती है, तो कॉन्फ़िगर की गई वॉइस रखने के बजाय उस भाषा की नेटिव वॉइस पर स्विच करें (जेंडर के अनुसार मैच की गई) |
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 |
voicemail_action | स्ट्रिंग | नहीं | prompt (डिफ़ॉल्ट), hangup, या message |
voicemail_message | स्ट्रिंग | नहीं | voicemail_action="message" होने पर उपयोग किया जाता है |
agent_name | स्ट्रिंग | नहीं | डैशबोर्ड और विजेट को रिपोर्ट किया जाने वाला डिस्प्ले नाम |
org_name | स्ट्रिंग | नहीं | एजेंट के पर्सोना के लिए संगठन का डिस्प्ले नाम |
tools | ऐरे | नहीं | इनलाइन फ़ंक्शन-टूल स्कीमा (Function Tools देखें) |
call_id | इंटीजर | नहीं | रिक्वेस्ट की कॉल आईडी का वैकल्पिक इको; अनदेखा किया जाता है |
क्योंकि prompt और voice आवश्यक हैं, {} या वैलिडेशन में विफल होने वाला कोई भी
रिस्पॉन्स कॉल को 422 के साथ अस्वीकार कर देता है — इस पाथ पर कोई
स्टैटिक-एजेंट फ़ॉलबैक नहीं है (वेबहुक मोड में किसी नंबर या की को
कोई एजेंट असाइन नहीं होता)।
रिस्पॉन्स आकार सीमा
उदाहरण हैंडलर
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({});
},
);फंक्शन टूल्स के साथ रिस्पॉन्स
टूल्स अटैच करें ताकि 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 | अधिक | गहन | सोचते समय ऑटो फिलर |
संबंधित
नॉन-ब्लॉकिंग कॉल-समाप्ति इवेंट।
tools[] और साइन किए गए एंडपॉइंट कॉन्ट्रैक्ट के लिए पूर्ण JSON स्कीमा।
telephony.incoming / web.incoming के लिए कई URLs सब्सक्राइब करें।
प्रति-कॉलर प्रॉम्प्ट्स, टूल्स और A/B टेस्ट के पैटर्न।