ThunderPhone 2.0 आता लाइव्ह आहे.स्वतःच सुरू करा—2¢/मिनिटपासून.घोषणा वाचा

Developer cookbook

प्रत्येक कॉलसाठी डायनॅमिक कॉन्फिगरेशन

तुमच्या नियंत्रणातील webhook मधील सानुकूल लॉजिकद्वारे, प्रत्येक येणाऱ्या कॉलसाठी स्वतंत्रपणे उत्तर देणारा एजंट निवडा — किंवा त्याचा prompt आणि सेटिंग्ज पुन्हा लिहा.

डीफॉल्टनुसार प्रत्येक फोन नंबर आणि प्रकाशित करण्यायोग्य कीला एक स्थिर एजंट नियुक्त केलेला असतो. तुम्हाला प्रत्येक कॉलरसाठी किंवा प्रत्येक व्हिजिटरसाठी सानुकूलन हवे असल्यास — VIP राउटिंग, लॉग-इन केलेल्या वापरकर्त्याचा संदर्भ, A/B prompt चाचण्या — webhook मोडवर स्विच करा आणि तुमच्या सर्व्हरला निर्णय घेऊ द्या.

हे कसे कार्य करते

  1. तुम्ही telephony.incoming (फोन) किंवा web.incoming (विजेट) इव्हेंटचे सदस्यत्व घेता. दोन्ही ब्लॉकिंग वेबहुक आहेत: कॉल पुढे सुरू ठेवण्यापूर्वी ThunderPhone तुमच्या प्रतिसादाची प्रतीक्षा करते—फोन कॉलसाठी 13 सेकंदांपर्यंत (एक पुनर्प्रयत्न समाविष्ट) आणि विजेट सत्रासाठी 10 सेकंद.
  2. ThunderPhone तुम्हाला {call_id, from_number, to_number} पाठवते (विजेट सत्रांमध्ये क्रमांकांऐवजी विजेट-विशिष्ट फील्ड असतात—विनंती स्कीमा पहा).
  3. तुमचा सर्व्हर एजंट कॉन्फिगरेशनने प्रतिसाद देतो (prompt, व्हॉइस, उत्पादन, टूल्स). ThunderPhone कॉलसाठी ते कॉन्फिगरेशन वापरते.
  4. कोणताही फॉलबॅक एजंट नाही. तुम्ही {} किंवा अवैध कॉन्फिगरेशन परत केल्यास, किंवा पुनर्प्रयत्न नंतरही विनंती अयशस्वी झाल्यास, फोन कॉल त्वरित समाप्त केला जातो आणि end_reason inbound_config_webhook_failed सह नोंदवला जातो; विजेट सत्राची विनंती अयशस्वी होते.

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" मधील प्रकाशित करण्यायोग्य की तयार करा:

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. हँडलर लागू करा

तीन मूलभूत नियम:

  • प्रत्येक विनंतीवर स्वाक्षरी सत्यापित करा (पहा वेबहुक स्वाक्षऱ्या सत्यापित करा). डेव्हलपमेंटमध्ये हे वगळू नका — एकदा योग्य करा आणि पुन्हा वापरा.
  • त्वरित प्रतिसाद द्या. फोन कॉलचा पहिला प्रयत्न 10 सेकंदांनंतर आणि संपूर्ण संवाद 13 सेकंदांनंतर बंद केला जातो, आणि प्रत्येक सेकंद कॉलरसाठी निःशब्द वेळ असतो. गरज असल्यास डेटाबेस लुकअप करा, पण डाउनस्ट्रीम LLM ना समकालिकपणे कॉल करू नका — डायनॅमिक prompt निर्मिती हवी असल्यास, आधीच गणना करून कॅश करा.
  • स्वच्छपणे फॉलबॅक करा. कोणत्याही अनपेक्षित स्थितीसाठी, डीफॉल्ट prompt आणि voice (किंवा जतन केलेला agent_id) सह उत्तर द्या. {} किंवा त्रुटी स्थिती परत केल्यास कॉल संपतो.
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स्ट्रिंग (आवश्यक)एजंटसाठी सिस्टम prompt
voiceस्ट्रिंग (आवश्यक)GET /v1/voices मधील व्हॉइस आयडी
productस्ट्रिंगडीफॉल्ट spark आहे. प्रायोगिक उत्पादने फक्त अनुमतीसूचीतील संस्थांसाठी उपलब्ध आहेत.
background_trackस्ट्रिंग | nullसभोवतालच्या ऑडिओचा आयडी
acknowledgement_prompt_modeस्ट्रिंगauto किंवा manual (फक्त ack-सह Storm)
acknowledgement_promptस्ट्रिंगमोड manual असल्यास आवश्यक
toolsअॅरेइनलाइन फंक्शन-टूल स्कीमा — फंक्शन टूल्स पहा

जतन केलेला एजंट ठेवा आणि व्हेरिएबल्स पुरवा

त्या संस्थेचा प्रति-कॉल डेटा असलेला सेव्ह केलेला एजंट वापरण्यासाठी {"agent_id": 12, "variables": {"name": "Ada"}} परत करा. त्याच्या prompt मध्ये {{name}} किंवा {{name|Friend}} असू शकते. Webhook व्हेरिएबल्स विनंती-स्तरीय व्हेरिएबल्सवर विलीन होतात; null असल्यास प्लेसहोल्डरचे डीफॉल्ट मूल्य किंवा काहीही दिले नसल्यास रिकामा मजकूर वापरला जातो. अंतिम मूल्ये आणि निराकरण न झालेली नावे कॉल तपशीलांमध्ये आणि पूर्णता webhooks मध्ये दिसतात. सेव्ह केलेल्या एजंटच्या प्रतिसादांमध्ये केवळ agent_id, variables आणि timezone स्वीकारले जातात. prompt असल्यास प्रतिसाद इनलाइन कॉन्फिगरेशन वापरतो आणि agent_id दुर्लक्षित करतो (यात null किंवा पूर्णांक नसलेल्या मेटाडेटाचाही समावेश आहे); इनलाइन prompt तरीही वैध असणे आवश्यक आहे. इनलाइन कॉन्फिगरेशन प्रतिसादांमध्ये variables देखील असू शकतात. सेव्ह केलेल्या एजंटचे प्रतिसाद फोन आणि विजेट या दोन्ही कॉल्सवर एजंटचे तैनात केलेले A/B विभाजन वापरतात, त्यानंतर व्हेरिएबल्स रेंडर करतात. मर्यादा आणि सत्र API समर्थनासाठी कॉल व्हेरिएबल्स पहा. ब्लॉकिंग कॉन्फिगरेशन लेगसी फोन-नंबर/संस्था URL किंवा webhook-मोड विजेट कीमधून येते; एंडपॉइंट-सिस्टमकडे येणारे इव्हेंट्स केवळ सूचना असतात.

प्रत्येक कॉलसाठी वेळ क्षेत्र सेट करा

एक एजंट वेगवेगळ्या वेळ क्षेत्रांतील संपर्कांना उत्तर देऊ शकतो. जतन केलेल्या एजंट किंवा इनलाइन प्रतिसादात IANA नाव असलेले timezone जोडा; त्यानंतर एजंट तारीख आणि वेळ सांगतो आणि या कॉलसाठी एजंटच्या स्वतःच्या वेळ क्षेत्राऐवजी त्या क्षेत्रातील वेळा सुचवतो:

{"agent_id": 12, "timezone": "America/Chicago", "variables": {"name": "Ada"}}

variables मध्ये टाइमस्टॅम्पऐवजी वेळ क्षेत्र पाठवा: कॉलदरम्यान एजंटचे घड्याळ चालू राहते आणि तुम्ही दिलेली वेळ कालबाह्य होते. IANA वेळ क्षेत्र नसलेले मूल्य दुर्लक्षित केले जाते आणि कॉल एजंटच्या वेळ क्षेत्रात जोडला जातो.

नमुने

लॉग-इन केलेल्या वापरकर्त्याचा संदर्भ

वेबहुक-मोड विजेट्समध्ये, व्हिजिटरच्या पेजला ते कोण आहेत हे आधीच माहित असते. विजेट 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() वर साधा स्विच वापरा.


पुढील पायऱ्या