ThunderPhone 2.0 હવે લાઇવ છે.સેલ્ફ-સર્વ, 2¢/મિનિટથી.જાહેરાત વાંચો

Developer cookbook

દરેક કૉલ માટે ગતિશીલ કૉન્ફિગરેશન

તમે નિયંત્રિત કરતા webhookમાં કસ્ટમ લોજિકના આધારે, દરેક આવનારા કૉલ માટે અલગથી જવાબ આપતો એજન્ટ પસંદ કરો — અથવા તેનો prompt અને સેટિંગ્સ ફરીથી લખો.

ડિફૉલ્ટ રીતે દરેક ફોન નંબર અને publishable key માટે એક સ્થિર એજન્ટ સોંપાયેલ હોય છે. જ્યારે તમને દરેક કૉલર માટે અથવા દરેક વિઝિટર માટે કસ્ટમાઇઝેશનની જરૂર હોય — VIP રાઉટિંગ, લૉગ-ઇન થયેલા વપરાશકર્તાનો સંદર્ભ, A/B prompt પરીક્ષણો — ત્યારે webhook-mode પર સ્વિચ કરો અને તમારા સર્વરને નિર્ણય લેવા દો.

તે કેવી રીતે કાર્ય કરે છે

  1. તમે telephony.incoming (ફોન) અથવા web.incoming (widget) ઇવેન્ટને સબ્સ્ક્રાઇબ કરો છો. બંને બ્લૉકિંગ webhooks છે: ThunderPhone કૉલ ચાલુ રાખતા પહેલાં તમારા પ્રતિસાદ માટે 10 સેકન્ડ સુધી રાહ જુએ છે.
  2. ThunderPhone તમને {call_id, from_number, to_number} મોકલે છે (widget સત્રોમાં નંબરોને બદલે widget-વિશિષ્ટ ફીલ્ડ હોય છે — request schema જુઓ).
  3. તમારો સર્વર એજન્ટ કૉન્ફિગરેશન (prompt, voice, product, tools) સાથે પ્રતિસાદ આપે છે. ThunderPhone કૉલ માટે તે કૉન્ફિગરેશનનો ઉપયોગ કરે છે.
  4. જો તમે {} પરત કરો, સમય સમાપ્ત થાય, અથવા ભૂલ આવે, તો સ્થિર રીતે સોંપાયેલ એજન્ટ 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 શામેલ હોય છે — તેને સાચવો; તમે તેનો ઉપયોગ signature verification માટે કરશો.

widget સત્રો માટે, તમારા 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"]
  }'

દરેક સત્ર શરૂ થાય ત્યારે widget આ URL પર POST કરશે.

2. હેન્ડલર અમલમાં મૂકો

ત્રણ સામાન્ય નિયમો:

  • દરેક વિનંતી પર સહી ચકાસો (જુઓ webhook સહી ચકાસો). ડેવલપમેન્ટમાં આ છોડશો નહીં — એકવાર યોગ્ય રીતે કરો અને ફરીથી ઉપયોગ કરો.
  • ઝડપથી પ્રતિસાદ આપો. દસ સેકન્ડની કડક મર્યાદા છે, અને દરેક સેકન્ડ કૉલર માટે મૌન સમય છે. જરૂર હોય તો ડેટાબેઝ લુકઅપ કરો, પરંતુ ડાઉનસ્ટ્રીમ LLM ને સિંક્રોનસ રીતે કૉલ કરશો નહીં — ડાયનેમિક prompt જનરેશન જોઈએ તો, પૂર્વ-ગણતરી કરીને કૅશ કરો.
  • સ્વચ્છ રીતે ફૉલબૅક કરો. કોઈપણ અનપેક્ષિત સ્થિતિએ {} પરત કરવું જોઈએ જેથી સ્થિર રીતે અસાઇન કરેલ એજન્ટ કૉલ સંભાળે.
FastAPI
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
Express
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સ્ટ્રિંગ (આવશ્યક)એજન્ટ માટે સિસ્ટમ પ્રોમ્પ્ટ
voiceસ્ટ્રિંગ (આવશ્યક)GET /v1/voices માંથી વૉઇસ id
productસ્ટ્રિંગડિફૉલ્ટ spark છે
background_trackસ્ટ્રિંગ | નલએમ્બિયન્ટ ઑડિયો id
acknowledgement_prompt_modeસ્ટ્રિંગauto અથવા manual (ફક્ત ack સાથેના Storm માટે)
acknowledgement_promptસ્ટ્રિંગમોડ manual હોય ત્યારે આવશ્યક
toolsએરેઇનલાઇન ફંક્શન-ટૂલ સ્કીમાઓ — ફંક્શન ટૂલ્સ જુઓ

સાચવેલ એજન્ટ રાખો અને વેરિએબલ્સ આપો

પ્રતિ-કૉલ ડેટા સાથે તે સંસ્થાના સાચવેલા એજન્ટનો ઉપયોગ કરવા માટે {"agent_id": 12, "variables": {"name": "Ada"}} પરત કરો. તેના પ્રોમ્પ્ટમાં {{name}} અથવા {{name|Friend}} હોઈ શકે છે. વેબહૂક વેરિએબલ્સ રિક્વેસ્ટ-સ્તરના વેરિએબલ્સ પર મર્જ થાય છે; નલ હોય ત્યારે પ્લેસહોલ્ડર ડિફૉલ્ટનો ઉપયોગ થાય છે, અથવા કંઈ આપવામાં ન હોય તો ખાલી ટેક્સ્ટનો ઉપયોગ થાય છે. અંતિમ મૂલ્યો અને ઉકેલાયા ન હોય તેવા નામો કૉલ વિગતો અને કમ્પ્લીશન વેબહૂક્સમાં દેખાય છે. સાચવેલા-એજન્ટના પ્રતિસાદો ફક્ત agent_id અને variables સ્વીકારે છે. જો prompt હાજર હોય, તો પ્રતિસાદ ઇનલાઇન કૉન્ફિગરેશનનો ઉપયોગ કરે છે અને agent_idને અવગણે છે (નલ અથવા બિન-પૂર્ણાંક મેટાડેટા સહિત); ઇનલાઇન પ્રોમ્પ્ટ હજુ પણ માન્ય હોવો જરૂરી છે. ઇનલાઇન કૉન્ફિગરેશન પ્રતિસાદોમાં variables પણ સામેલ હોઈ શકે છે. સાચવેલા-એજન્ટના પ્રતિસાદો ફોન અને વિજેટ બંને કૉલ્સ પર એજન્ટનો ડિપ્લોય કરેલ A/B સ્પ્લિટ ઉપયોગ કરે છે, પછી વેરિએબલ્સ રેન્ડર કરે છે. કૉલ વેરિએબલ્સ મર્યાદાઓ અને સેશન API સપોર્ટ માટે જુઓ. બ્લોકિંગ કૉન્ફિગરેશન લેગસી ફોન-નંબર/સંસ્થા URL અથવા વેબહૂક-મોડ વિજેટ કીમાંથી આવે છે; એન્ડપૉઇન્ટ-સિસ્ટમ ઇનકમિંગ ઇવેન્ટ્સ માત્ર સૂચનાઓ છે.

પેટર્ન્સ

લૉગ-ઇન થયેલા વપરાશકર્તાનો સંદર્ભ

વેબહૂક-મોડ વિજેટ્સમાં, વિઝિટરનું પેજ પહેલેથી જ જાણે છે કે તેઓ કોણ છે. તમારા વેબહૂકને વિજેટ SDK ફૉર્વર્ડ કરે તેવા ક્વેરી સ્ટ્રિંગ પેરામીટર સાથે કૉલ કરો (?customer_id=123) અને સર્વર-સાઇડ ગ્રાહક શોધો.

A/B પ્રોમ્પ્ટ રોલઆઉટ

તમે આ જાતે બનાવો તે પહેલાં, નોંધો કે ThunderPhone પાસે મૂળભૂત પ્રયોગો સુવિધા છે (/dashboard/experiments અને એજન્ટ બિલ્ડરના A/B ટૅબમાં), જે વેરિઅન્ટ્સ વ્યાખ્યાયિત કરે છે, ટ્રાફિક વહેંચે છે અને દરેક વેરિઅન્ટના પરિણામોની તુલના કરે છે — વેબહૂકની જરૂર નથી.

જો તમને તેમ છતાં વેબહૂક-બાજુનું નિયંત્રણ જોઈએ: call_id હૅશ કરો → બકેટ; 0..49 માટે પ્રોમ્પ્ટ A અને 50..99 માટે પ્રોમ્પ્ટ B આપો. તમે પસંદ કરેલો બકેટ તમારા પોતાના DBમાં રેકોર્ડ કરો અને પછી પૂર્ણ થયેલા કૉલના ગ્રેડ સાથે તેનો સંબંધ સ્થાપિત કરો.

સમય-આધારિત રૂટિંગ

વ્યવસાયિક સમય → "લાઇવ સપોર્ટ" એજન્ટ; કામકાજ પછીનો સમય → "સંદેશ લો" એજન્ટ. તમારા હેન્ડલરમાં new Date().getUTCHours() પર સીધું સ્વિચ કરો.


આગળનાં પગલાં