ThunderPhone 2.0 ਹੁਣ ਲਾਈਵ ਹੈ।ਸੈਲਫ਼-ਸਰਵਿਸ—2¢/ਮਿੰਟ ਤੋਂਐਲਾਨ ਪੜ੍ਹੋ

Developer cookbook

ਹਰ ਕਾਲ ਲਈ ਡਾਇਨਾਮਿਕ ਸੰਰਚਨਾ

ਤੁਹਾਡੇ ਨਿਯੰਤਰਣ ਹੇਠਲੇ webhook ਵਿੱਚ ਕਸਟਮ ਤਰਕ ਦੇ ਆਧਾਰ

ਮੂਲ ਰੂਪ ਵਿੱਚ ਹਰ ਫ਼ੋਨ ਨੰਬਰ ਅਤੇ ਪ੍ਰਕਾਸ਼ਯੋਗ ਕੀ ਨਾਲ ਇੱਕ ਸਥਿਰ ਏਜੰਟ ਨਿਰਧਾਰਤ ਹੁੰਦਾ ਹੈ। ਜਦੋਂ ਤੁਹਾਨੂੰ ਹਰ ਕਾਲਰ ਲਈ ਜਾਂ ਹਰ ਵਿਜ਼ਟਰ ਲਈ ਕਸਟਮਾਈਜ਼ੇਸ਼ਨ ਚਾਹੀਦੀ ਹੋਵੇ — VIP ਰੂਟਿੰਗ, ਲੌਗ-ਇਨ ਵਰਤੋਂਕਾਰ ਸੰਦਰਭ, A/B prompt ਟੈਸਟ — ਤਾਂ ਵੈੱਬਹੁੱਕ ਮੋਡ ਵਰਤੋ ਅਤੇ ਆਪਣੇ ਸਰਵਰ ਨੂੰ ਫ਼ੈਸਲਾ ਕਰਨ ਦਿਓ।

ਇਹ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ

  1. ਤੁਸੀਂ telephony.incoming (ਫ਼ੋਨ) ਜਾਂ web.incoming (ਵਿਜੇਟ) ਇਵੈਂਟ ਦੀ ਸਬਸਕ੍ਰਿਪਸ਼ਨ ਲੈਂਦੇ ਹੋ। ਦੋਵੇਂ ਬਲਾਕਿੰਗ ਵੈੱਬਹੁੱਕ ਹਨ: ThunderPhone ਕਾਲ ਜਾਰੀ ਰੱਖਣ ਤੋਂ ਪਹਿਲਾਂ ਤੁਹਾਡੇ ਜਵਾਬ ਲਈ ਵੱਧ ਤੋਂ ਵੱਧ 10 ਸਕਿੰਟ ਉਡੀਕ ਕਰਦਾ ਹੈ।
  2. ThunderPhone ਤੁਹਾਨੂੰ {call_id, from_number, to_number} ਭੇਜਦਾ ਹੈ (ਵਿਜੇਟ ਸੈਸ਼ਨਾਂ ਵਿੱਚ ਨੰਬਰਾਂ ਦੀ ਥਾਂ ਵਿਜੇਟ-ਵਿਸ਼ੇਸ਼ ਫ਼ੀਲਡ ਹੁੰਦੇ ਹਨ — ਰਿਕਵੇਸਟ ਸਕੀਮਾ ਦੇਖੋ)।
  3. ਤੁਹਾਡਾ ਸਰਵਰ ਏਜੰਟ ਕੌਂਫਿਗਰੇਸ਼ਨ ਨਾਲ ਜਵਾਬ ਦਿੰਦਾ ਹੈ (prompt, ਆਵਾਜ਼, ਉਤਪਾਦ, ਟੂਲ)। ThunderPhone ਉਸ ਕਾਲ ਲਈ ਉਹ ਕੌਂਫਿਗਰੇਸ਼ਨ ਵਰਤਦਾ ਹੈ।
  4. ਜੇ ਤੁਸੀਂ {} ਵਾਪਸ ਕਰਦੇ ਹੋ, ਸਮਾਂ ਸਮਾਪਤ ਹੋ ਜਾਂਦਾ ਹੈ, ਜਾਂ ਗਲਤੀ ਆਉਂਦੀ ਹੈ, ਤਾਂ ਸਥਿਰ ਤੌਰ 'ਤੇ ਨਿਰਧਾਰਤ ਏਜੰਟ ਨੂੰ ਫਾਲਬੈਕ ਵਜੋਂ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ। ਸੁਰੱਖਿਅਤ ਮੂਲ ਵਿਕਲਪ।

1. ਵੈੱਬਹੁੱਕ ਟਿਕਾਣਾ ਕੌਂਫਿਗਰ ਕਰੋ

ਫ਼ੋਨ ਨੰਬਰਾਂ ਲਈ, ਆਪਣੇ ਐਂਡਪੁਆਇੰਟ ਨੂੰ 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 ਸ਼ਾਮਲ ਹੁੰਦਾ ਹੈ — ਇਸਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰੋ; ਤੁਸੀਂ ਇਸਨੂੰ ਦਸਤਖ਼ਤ ਤਸਦੀਕ ਲਈ ਵਰਤੋਗੇ।

ਵਿਜੇਟ ਸੈਸ਼ਨਾਂ ਲਈ, ਆਪਣੇ ਐਂਡਪੁਆਇੰਟ 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. ਹੈਂਡਲਰ ਲਾਗੂ ਕਰੋ

ਤਿੰਨ ਮੁੱਢਲੇ ਨਿਯਮ:

  • ਹਰ ਬੇਨਤੀ ਉੱਤੇ ਦਸਤਖ਼ਤ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ (ਵੇਖੋ ਵੈੱਬਹੁੱਕ ਦਸਤਖ਼ਤਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ)। ਡਿਵੈਲਪਮੈਂਟ ਵਿੱਚ ਵੀ ਇਸਨੂੰ ਨਾ ਛੱਡੋ — ਇੱਕ ਵਾਰ ਸਹੀ ਕਰੋ ਅਤੇ ਮੁੜ ਵਰਤੋ।
  • ਤੇਜ਼ੀ ਨਾਲ ਜਵਾਬ ਦਿਓ। ਦਸ ਸਕਿੰਟ ਵੱਧ ਤੋਂ ਵੱਧ ਸੀਮਾ ਹੈ, ਅਤੇ ਹਰ ਸਕਿੰਟ ਕਾਲਰ ਲਈ ਖਾਮੋਸ਼ੀ ਹੁੰਦਾ ਹੈ। ਲੋੜ ਪਏ ਤਾਂ ਡਾਟਾਬੇਸ ਲੁੱਕਅੱਪ ਕਰੋ, ਪਰ ਡਾਊਨਸਟ੍ਰੀਮ 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ਸਟ੍ਰਿੰਗ (ਲਾਜ਼ਮੀ)ਏਜੰਟ ਲਈ ਸਿਸਟਮ prompt
voiceਸਟ੍ਰਿੰਗ (ਲਾਜ਼ਮੀ)GET /v1/voices ਤੋਂ ਵੌਇਸ id
productਸਟ੍ਰਿੰਗਡਿਫਾਲਟ spark ਹੈ
background_trackਸਟ੍ਰਿੰਗ | nullਐਂਬੀਅੰਟ ਆਡੀਓ id
acknowledgement_prompt_modeਸਟ੍ਰਿੰਗauto ਜਾਂ manual (ਸਿਰਫ਼ ack ਵਾਲੇ Storm ਲਈ)
acknowledgement_promptਸਟ੍ਰਿੰਗਜਦੋਂ ਮੋਡ manual ਹੋਵੇ ਤਾਂ ਲਾਜ਼ਮੀ
toolsਐਰੇਇਨਲਾਈਨ ਫੰਕਸ਼ਨ-ਟੂਲ ਸਕੀਮਾ — Function Tools ਵੇਖੋ

ਸੇਵ ਕੀਤਾ ਏਜੰਟ ਰੱਖੋ ਅਤੇ ਵੇਰੀਏਬਲ ਦਿਓ

ਉਸ ਸੰਗਠਨ ਦੇ ਸੇਵ ਕੀਤੇ ਏਜੰਟ ਨੂੰ ਪ੍ਰਤੀ-ਕਾਲ ਡਾਟਾ ਨਾਲ ਵਰਤਣ ਲਈ {"agent_id": 12, "variables": {"name": "Ada"}} ਵਾਪਸ ਕਰੋ। ਇਸ ਦੇ prompt ਵਿੱਚ {{name}} ਜਾਂ {{name|Friend}} ਹੋ ਸਕਦਾ ਹੈ। ਵੈੱਬਹੁੱਕ ਵੇਰੀਏਬਲ ਬੇਨਤੀ-ਪੱਧਰ ਦੇ ਵੇਰੀਏਬਲਾਂ ਨੂੰ ਮਿਲਾ ਕੇ ਓਵਰਰਾਈਡ ਕਰਦੇ ਹਨ; null ਪਲੇਸਹੋਲਡਰ ਡਿਫਾਲਟ ਵਰਤਦਾ ਹੈ, ਜਾਂ ਜੇ ਕੋਈ ਨਾ ਦਿੱਤਾ ਹੋਵੇ ਤਾਂ ਖਾਲੀ ਟੈਕਸਟ ਵਰਤਦਾ ਹੈ। ਅੰਤਿਮ ਮੁੱਲ ਅਤੇ ਅਣਸੁਲਝੇ ਨਾਮ ਕਾਲ ਵੇਰਵਿਆਂ ਅਤੇ ਕੰਪਲੀਸ਼ਨ ਵੈੱਬਹੁੱਕਾਂ ਵਿੱਚ ਦਿਖਾਈ ਦਿੰਦੇ ਹਨ। ਸੇਵ ਕੀਤੇ ਏਜੰਟ ਦੇ ਜਵਾਬ ਸਿਰਫ਼ agent_id ਅਤੇ variables ਸਵੀਕਾਰ ਕਰਦੇ ਹਨ। ਜੇ prompt ਮੌਜੂਦ ਹੋਵੇ, ਤਾਂ ਜਵਾਬ ਇਨਲਾਈਨ ਕੌਂਫਿਗਰੇਸ਼ਨ ਵਰਤਦਾ ਹੈ ਅਤੇ agent_id ਨੂੰ ਅਣਡਿੱਠਾ ਕਰਦਾ ਹੈ (null ਜਾਂ ਗੈਰ-ਪੂਰਨ ਅੰਕ ਮੈਟਾਡੇਟਾ ਸਮੇਤ); ਇਨਲਾਈਨ prompt ਫਿਰ ਵੀ ਵੈਧ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ। ਇਨਲਾਈਨ ਕੌਂਫਿਗਰੇਸ਼ਨ ਜਵਾਬਾਂ ਵਿੱਚ variables ਵੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੇ ਹਨ। ਸੇਵ ਕੀਤੇ ਏਜੰਟ ਦੇ ਜਵਾਬ ਫੋਨ ਅਤੇ ਵਿਜਿਟ ਦੋਵਾਂ ਕਾਲਾਂ 'ਤੇ ਏਜੰਟ ਦੀ ਡਿਪਲੋਇ ਕੀਤੀ A/B ਵੰਡ ਵਰਤਦੇ ਹਨ, ਫਿਰ ਵੇਰੀਏਬਲ ਰੈਂਡਰ ਕਰਦੇ ਹਨ। ਸੀਮਾਵਾਂ ਅਤੇ ਸੈਸ਼ਨ API ਸਹਾਇਤਾ ਲਈ ਕਾਲ ਵੇਰੀਏਬਲ ਵੇਖੋ। ਬਲਾਕਿੰਗ ਕੌਂਫਿਗਰੇਸ਼ਨ ਪੁਰਾਣੇ ਫੋਨ-ਨੰਬਰ/ਸੰਗਠਨ URL ਜਾਂ ਵੈੱਬਹੁੱਕ-ਮੋਡ ਵਿਜਿਟ ਕੀ ਤੋਂ ਆਉਂਦੀ ਹੈ; ਐਂਡਪੌਇੰਟ-ਸਿਸਟਮ ਇਨਕਮਿੰਗ ਇਵੈਂਟ ਸਿਰਫ਼ ਸੂਚਨਾਵਾਂ ਹਨ।

ਪੈਟਰਨ

ਲੌਗ-ਇਨ ਯੂਜ਼ਰ ਸੰਦਰਭ

ਵੈੱਬਹੁੱਕ-ਮੋਡ ਵਿਜਿਟਾਂ ਵਿੱਚ, ਵਿਜ਼ਿਟਰ ਦੇ ਪੇਜ ਨੂੰ ਪਹਿਲਾਂ ਹੀ ਪਤਾ ਹੁੰਦਾ ਹੈ ਕਿ ਉਹ ਕੌਣ ਹਨ। ਆਪਣੇ ਵੈੱਬਹੁੱਕ ਨੂੰ ਉਸ ਕਵੇਰੀ ਸਟ੍ਰਿੰਗ ਪੈਰਾਮੀਟਰ ਨਾਲ ਕਾਲ ਕਰੋ ਜਿਸ ਨੂੰ ਵਿਜਿਟ 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() 'ਤੇ ਸਿੱਧਾ ਸਵਿਚ ਕਰੋ।


ਅਗਲੇ ਕਦਮ