દરેક કૉલ માટે ડાયનેમિક કન્ફિગરેશન
ડિફૉલ્ટ રૂપે દરેક ફોન નંબર અને publishable key ને એક સ્થિર એજન્ટ સોંપવામાં આવે છે. જ્યારે તમને દરેક કૉલર માટે અથવા દરેક વિઝિટર માટે કસ્ટમાઇઝેશનની જરૂર હોય — VIP રાઉટિંગ, લૉગ-ઇન થયેલા યુઝરનો કોન્ટેક્સ્ટ, A/B prompt પરીક્ષણો — ત્યારે webhook-mode પર સ્વિચ કરો અને તમારા સર્વરને નિર્ણય લેવા દો.
તે કેવી રીતે કાર્ય કરે છે
- તમે
telephony.incoming(ફોન) અથવાweb.incoming(વિજેટ) ઇવેન્ટને સબ્સ્ક્રાઇબ કરો છો. બંને બ્લૉકિંગ webhooks છે: ThunderPhone કૉલ ચાલુ રાખતા પહેલાં તમારા પ્રતિસાદ માટે 10 સેકન્ડ સુધી રાહ જુએ છે. - ThunderPhone તમને
{call_id, from_number, to_number}મોકલે છે (વિજેટ સેશન્સમાં નંબરોના બદલે વિજેટ-વિશિષ્ટ ફીલ્ડ્સ હોય છે — રિક્વેસ્ટ સ્કીમા જુઓ). - તમારો સર્વર એજન્ટ કૉન્ફિગરેશન (prompt, voice, product, tools) સાથે પ્રતિસાદ આપે છે. ThunderPhone કૉલ માટે તે કૉન્ફિગરેશનનો ઉપયોગ કરે છે.
- જો તમે
{}પરત કરો, સમયસમાપ્તિ થાય, અથવા ભૂલ આવે, તો સ્થિર રીતે સોંપાયેલ એજન્ટ fallback તરીકે વપરાય છે. સુરક્ષિત ડિફૉલ્ટ.
1. webhook ડેસ્ટિનેશન કૉન્ફિગર કરો
ફોન કૉલ્સ
ફોન નંબરો માટે, તમારા endpoint ને telephony.incoming માટે સબ્સ્ક્રાઇબ કરો:
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "Prod call-incoming",
"url": "https://example.com/thunderphone/incoming",
"events": ["telephony.incoming"]
}'
પ્રતિસાદમાં એક વખત ઉપયોગ કરી શકાય તેવું secret શામેલ હોય છે — તેને સાચવો; તમે તેનો ઉપયોગ
સિગ્નેચર વેરિફિકેશન માટે કરશો.
વેબ વિજેટ
વિજેટ સેશન્સ માટે, તમારા endpoint URL સાથે સમાવિષ્ટ mode="webhook" માં
publishable key બનાવો:
curl -X POST https://api.thunderphone.com/v1/publishable-key \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Dynamic widget",
"mode": "webhook",
"webhook_url": "https://example.com/thunderphone/widget-incoming",
"allowed_domains": ["example.com"]
}'
દરેક સેશન શરૂ થવા પર વિજેટ આ URL પર POST કરશે.
2. હેન્ડલર અમલમાં મૂકો
ત્રણ મુખ્ય નિયમો:
- દરેક વિનંતી પર સહી ચકાસો (જુઓ વેબહુક સહી ચકાસો). ડેવલપમેન્ટમાં આ છોડશો નહીં — એક વાર યોગ્ય રીતે અમલમાં મૂકો અને ફરીથી વાપરો.
- ઝડપથી પ્રતિસાદ આપો. દસ સેકન્ડ સખત મર્યાદા છે, અને દરેક સેકન્ડ કૉલર માટે નિઃશબ્દ સમય છે. જરૂર હોય તો ડેટાબેઝ લુકઅપ કરો, પરંતુ ડાઉનસ્ટ્રીમ LLMs ને સિંક્રોનસ રીતે કૉલ કરશો નહીં — ડાયનેમિક prompt જનરેશન જોઈએ તો પહેલેથી ગણતરી કરીને કૅશ કરો.
- સ્વચ્છ રીતે ફૉલબૅક કરો. કોઈપણ અનપેક્ષિત સ્થિતિએ
{}પરત કરવું જોઈએ જેથી સ્થિર રીતે સોંપાયેલ એજન્ટ કૉલ સંભાળી શકે.
import hashlib
import hmac
import json
import os
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]
def verify(body: bytes, sig: str) -> bool:
expected = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig or "")
@app.post("/thunderphone/incoming")
async def incoming(request: Request):
body = await request.body()
if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
raise HTTPException(401)
event = json.loads(body)
if event["type"] not in ("telephony.incoming", "web.incoming"):
return {} # fall back to default
caller = event["data"]["from_number"]
# Cheap DB lookup: is this a known VIP?
customer = lookup_customer(caller)
if customer and customer.tier == "vip":
return {
"prompt": f"You are a VIP concierge for {customer.name}. Be proactive…",
"voice": "john",
"product": "storm-base",
}
return {} # default agent handles non-VIPs
def lookup_customer(phone: str):
# ... your CRM integration ...
pass
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;
function verify(body, sig) {
const expected = crypto.createHmac("sha256", SECRET).update(body).digest("hex");
return sig &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}
app.post(
"/thunderphone/incoming",
express.raw({ type: "application/json" }),
async (req, res) => {
if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
const IMPORTANT_TYPES = new Set([
"telephony.incoming",
"web.incoming",
]);
if (!IMPORTANT_TYPES.has(event.type)) return res.json({});
const customer = await lookupCustomer(event.data.from_number);
if (customer?.tier === "vip") {
return res.json({
prompt: `You are a VIP concierge for ${customer.name}. Be proactive…`,
voice: "john",
product: "storm-base",
});
}
res.json({}); // fall back to default agent
},
);
3. પ્રતિસાદ સ્કીમા
પ્રતિસાદ બોડી ઇનકમિંગ કૉલ પ્રતિસાદ સ્કીમા સાથે બરાબર મેળ ખાય છે. સામાન્ય રીતે વપરાતા ફીલ્ડ્સ:
| ફીલ્ડ | પ્રકાર | વર્ણન |
|---|---|---|
prompt | સ્ટ્રિંગ (જરૂરી) | એજન્ટ માટેનો સિસ્ટમ prompt |
voice | સ્ટ્રિંગ (જરૂરી) | GET /v1/voices માંથી વૉઇસ ID |
product | સ્ટ્રિંગ | ડિફૉલ્ટ spark છે |
background_track | સ્ટ્રિંગ | નલ | એમ્બિયન્ટ ઑડિયો ID |
acknowledgement_prompt_mode | સ્ટ્રિંગ | auto અથવા manual (ફક્ત સ્વીકૃતિ સાથેના Storm માટે) |
acknowledgement_prompt | સ્ટ્રિંગ | મોડ manual હોય ત્યારે જરૂરી |
tools | એરે | ઇનલાઇન ફંક્શન-ટૂલ સ્કીમા — જુઓ ફંક્શન ટૂલ્સ |
પેટર્ન્સ
લૉગિન કરેલા વપરાશકર્તાનો સંદર્ભ
વેબહૂક-મોડ વિજેટ્સમાં, મુલાકાતીના પેજને પહેલેથી જ ખબર હોય છે કે તેઓ કોણ છે.
વિજેટ SDK ફોરવર્ડ કરે તેવા ક્વેરી સ્ટ્રિંગ પેરામીટર (?customer_id=123) સાથે તમારા વેબહૂકને કૉલ કરો અને સર્વર-સાઇડ પર ગ્રાહકને શોધો.
A/B prompt રોલઆઉટ
તમે આ જાતે બનાવો તે પહેલાં, નોંધ લો કે ThunderPhone માં નેટિવ
પ્રયોગો ફીચર
(/dashboard/experiments અને એજન્ટ બિલ્ડરની A/B ટૅબ) છે, જે
વેરિઅન્ટ્સ નિર્ધારિત કરે છે, ટ્રાફિક વહેંચે છે અને દરેક વેરિઅન્ટના પરિણામોની સરખામણી કરે છે —
વેબહૂકની જરૂર નથી.
જો તમને તેમ છતાં વેબહૂક-સાઇડ નિયંત્રણની જરૂર હોય: call_id ને હૅશ કરો → બકેટ;
0..49 માટે prompt A અને 50..99 માટે prompt B આપો. તમે પસંદ કરેલો
બકેટ તમારા પોતાના DB માં રેકોર્ડ કરો અને પછી પૂર્ણ થયેલા કૉલના ગ્રેડ સાથે
તેનો સંબંધ સ્થાપિત કરો.
સમય-આધારિત રૂટિંગ
કાર્યકાળ → "લાઇવ સપોર્ટ" એજન્ટ; કાર્યકાળ પછી → "સંદેશ લો"
એજન્ટ. તમારા હેન્ડલરમાં new Date().getUTCHours() પર સરળ સ્વિચ કરો.