Usanidi unaobadilika kwa kila simu
Kwa chaguo-msingi, kila nambari ya simu na ufunguo unaoweza kuchapishwa una ejenti tuli iliyowekwa. Unapohitaji ubinafsishaji kwa kila mpigaji au kwa kila mgeni — uelekezaji wa VIP, muktadha wa mtumiaji aliyeingia, majaribio ya prompt ya A/B — badilisha hadi hali ya webhook na uruhusu seva yako iamue.
Jinsi inavyofanya kazi
- Unajiandikisha kwa tukio la
telephony.incoming(simu) auweb.incoming(wijeti). Zote ni webhook zinazosubiri: ThunderPhone husubiri hadi sekunde 10 kwa jibu lako kabla ya kuendelea na simu. - ThunderPhone hukutumia
{call_id, from_number, to_number}(vipindi vya wijeti hubeba sehemu mahususi za wijeti badala ya nambari — tazama schema ya ombi). - Seva yako hujibu kwa usanidi wa ejenti (prompt, sauti, bidhaa, zana). ThunderPhone hutumia usanidi huo kwa simu.
- Ukirejesha
{}, muda ukiisha, au hitilafu ikitokea, ejenti iliyowekwa tuli hutumika kama mbadala. Chaguo-msingi salama.
1. Sanidi eneo la webhook
Simu
Kwa nambari za simu, jiandikishe endpoint yako kwa 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"]
}'
Jibu linajumuisha secret ya matumizi ya mara moja — ihifadhi; utaitumia
kwa uthibitishaji wa sahihi.
Wijeti ya wavuti
Kwa vipindi vya wijeti, unda ufunguo unaoweza kuchapishwa katika mode="webhook"
ukiwa na URL ya endpoint yako iliyojumuishwa:
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"]
}'
Wijeti itatuma POST kwa URL hii kila kipindi kinapoanza.
2. Tekeleza kishughulikiaji
Kanuni tatu za kukumbuka:
- Thibitisha sahihi kwenye kila ombi (angalia Thibitisha sahihi za webhook). Usiruke hii wakati wa dev — ifanye kwa usahihi mara moja na uitumie tena.
- Jibu haraka. Sekunde kumi ndicho kikomo cha juu, na kila sekunde ni ukimya kwa mpigaji simu. Fanya utafutaji wa hifadhidata ukiuhitaji, lakini usiite LLM za hatua za chini kwa usawazishaji — ukitaka kutengeneza prompt badilifu, zifanye mapema na uzihifadhi kwenye cache.
- Tumia njia mbadala kwa usafi. Hali yoyote isiyotarajiwa inapaswa kurejesha
{}ili ejenti iliyopewa kwa njia tuli ishughulikie simu.
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. Schema ya jibu
Mwili wa jibu unalingana na schema ya jibu la simu inayoingia hasa. Sehemu zinazotumiwa mara nyingi:
| Sehemu | Aina | Maelezo |
|---|---|---|
prompt | string (inahitajika) | System prompt ya ejenti |
voice | string (inahitajika) | Kitambulisho cha sauti kutoka GET /v1/voices |
product | string | Chaguo-msingi ni spark |
background_track | string | null | Kitambulisho cha sauti ya mazingira |
acknowledgement_prompt_mode | string | auto au manual (Storm-with-ack pekee) |
acknowledgement_prompt | string | Inahitajika wakati modi ni manual |
tools | array | Schema za inline za function-tool — angalia Function Tools |
Miundo
Muktadha wa mtumiaji aliyeingia
Katika wijeti za hali ya webhook, ukurasa wa mgeni tayari unajua yeye ni nani. Piga webhook yako kwa kutumia kigezo cha mfuatano wa hoja ambacho SDK ya wijeti hutuma mbele (?customer_id=123) na umtafute mteja upande wa seva.
Utoaji wa prompt wa A/B
Kabla hujatengeneza hii mwenyewe, kumbuka kwamba ThunderPhone ina kipengele asilia cha Majaribio
(/dashboard/experiments na kichupo cha A/B cha kijenzi cha ejenti) kinachofafanua vibadala, kugawa trafiki, na kulinganisha matokeo kwa kila kibadala —
hakuna webhook inayohitajika.
Ikiwa bado unahitaji udhibiti wa upande wa webhook: fanya hash ya call_id → bucket;
toa prompt A kwa 0..49 na prompt B kwa 50..99. Rekodi bucket uliyochagua kwenye DB yako mwenyewe na baadaye uihusishe na daraja la simu iliyokamilika.
Uelekezaji kulingana na muda
Saa za kazi → ejenti wa "msaada wa moja kwa moja"; baada ya saa za kazi → ejenti wa "chukua ujumbe"
. Badiliko rahisi kulingana na new Date().getUTCHours() katika handler yako.
Hatua zinazofuata
Miundo sahihi ya ombi + jibu, ikijumuisha kila ufunguo wa usanidi.
Sanidi HMAC kwa usahihi mara moja; itumie tena kila mahali.
Changanya uelekezaji unaobadilika na zana za kila ejenti.
Majaribio ya kurudia, mpangilio, muda wa kuisha.