telephony.incoming / web.incoming
જ્યારે ઇનબાઉન્ડ ફોન કૉલ કોઈ એજન્ટ સોંપાયેલ ન હોય તેવા
નંબર પર પહોંચે, અથવા વેબ વિજેટ સત્ર
mode="webhook"માં પબ્લિશેબલ કી પર શરૂ થાય, ત્યારે ThunderPhone તમારા
લેગસી વેબહૂક URL પર બ્લોકિંગ
telephony.incoming / web.incoming વિનંતી મોકલે છે અને કૉન્ફિગરેશન પ્રતિસાદ માટે
10 સેકન્ડ સુધી રાહ જુએ છે. દરેક કૉલ માટે prompt, અવાજ અને ટૂલ્સને
ડાયનેમિક રીતે પસંદ કરવા માટે આ વિનિમયનો ઉપયોગ કરો —
સંપૂર્ણ પેટર્ન માટે ડાયનેમિક કૉલ કૉન્ફિગરેશન માર્ગદર્શિકા
જુઓ.
બ્લોકિંગ વિનિમયમાં કોઈ ફૉલબૅક નથી: જો તમારું હેન્ડલર નૉન-2xx સ્ટેટસ
પરત કરે, સમયસમાપ્તિ થાય, અથવા વૅલિડેશન નિષ્ફળ જાય તેવું કૉન્ફિગ પરત કરે,
તો કૉલ નકારવામાં આવે છે (ફોન કૉલ કનેક્ટ થતો નથી; વિજેટ સત્ર વિનંતી
502/422 સાથે નિષ્ફળ જાય છે). ઝડપથી જવાબ આપો — તમે નિર્ણય લો છો
ત્યારે કૉલર રિંગબેક સાંભળી રહ્યો હોય છે.
વિનંતી પેલોડ
ફોન કૉલ્સ માટે (telephony.incoming):
{
"type": "telephony.incoming",
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}
| ફીલ્ડ | પ્રકાર | વર્ણન |
|---|---|---|
call_id | ઇન્ટિજર | કૉલ id — આ કૉલ માટેની તમામ ઇવેન્ટ્સમાં સ્થિર |
from_number | સ્ટ્રિંગ | E.164 કૉલર નંબર |
to_number | સ્ટ્રિંગ | 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 | ઇન્ટિજર | કૉલ id |
origin_domain | સ્ટ્રિંગ | વિજેટ હોસ્ટ કરતા પેજનું ઓરિજિન |
publishable_key_prefix | સ્ટ્રિંગ | સત્ર ખોલનાર પબ્લિશેબલ કીના પ્રથમ અક્ષરો |
language, primary_language | સ્ટ્રિંગ | વિજેટ સત્રે ભાષા ઓવરરાઇડની વિનંતી કરી હોય ત્યારે હાજર |
voice | સ્ટ્રિંગ | વિજેટ સત્રે અવાજ ઓવરરાઇડની વિનંતી કરી હોય ત્યારે હાજર |
website_context | સ્ટ્રિંગ | વિજેટે પ્રતિ-સત્ર પેજ કન્ટેક્સ્ટ પસાર કર્યો હોય ત્યારે હાજર |
પ્રતિસાદ સ્કીમા
આ કોલ માટે એજન્ટ કન્ફિગરેશનનું વર્ણન કરતું JSON ઑબ્જેક્ટ પરત કરો.
prompt અને voice આવશ્યક છે; બાકીનું બધું વૈકલ્પિક છે.
{
"prompt": "You are a helpful booking assistant for Acme Restaurant.",
"voice": "john",
"product": "spark",
"background_track": null,
"tools": []
}
| ફીલ્ડ | પ્રકાર | આવશ્યક | વર્ણન |
|---|---|---|---|
prompt | સ્ટ્રિંગ | હા | એજન્ટને નિયંત્રિત કરતો સિસ્ટમ prompt |
voice | સ્ટ્રિંગ | હા | GET /v1/voices માંથી વૉઇસ ID, ઉદાહરણ તરીકે 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 |
storm_feedback_mode | સ્ટ્રિંગ | ના | none, acknowledgement (ડિફૉલ્ટ), અથવા tick |
language | સ્ટ્રિંગ | ના | primary_language માટેનું સંક્ષિપ્ત રૂપ |
primary_language | સ્ટ્રિંગ | ના | ભાષા કોડ, સામાન્યકૃત (ડિફૉલ્ટ en). ઉકેલી ન શકાય તેવા કોડ્સ કોલ નકારી કાઢે છે |
has_additional_languages | બુલિયન | ના | ડિફૉલ્ટ false |
additional_languages | સ્ટ્રિંગની એરે | ના | એજન્ટ બદલી શકે તેવી વધારાની ભાષાઓ |
background_track | સ્ટ્રિંગ | નલ | ના | પૃષ્ઠભૂમિ ઑડિયો ID અથવા null |
acknowledgement_prompt_mode | સ્ટ્રિંગ | ના | auto (ડિફૉલ્ટ) અથવા manual (Storm-with-ack પ્રોડક્ટ્સ) |
acknowledgement_prompt | સ્ટ્રિંગ | ના | acknowledgement_prompt_mode="manual" હોય ત્યારે વપરાય છે |
silence_interval_seconds | ઇન્ટિજર | નલ | ના | 5–120. સંપર્ક-ચકાસણી પહેલાં કોલરનું મૌન રહેવાની સેકન્ડ્સ |
silence_max_checkins | ઇન્ટિજર | નલ | ના | 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 | એરે | ના | ઇનલાઇન ફંક્શન-ટૂલ સ્કીમાઓ (ફંક્શન ટૂલ્સ જુઓ) |
call_id | ઇન્ટિજર | ના | રિક્વેસ્ટના કોલ 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 સબ્સ્ક્રાઇબ કરો.
દરેક કોલર માટેના prompts, ટૂલ્સ અને A/B ટેસ્ટ માટેની પેટર્ન્સ.