ThunderPhone 2.0 on nüüd saadaval.Iseteenindusena alates 2 senti/min.Loe uudist

Developer cookbook

Dünaamiline kõnepõhine seadistamine

Vali vastav häälagent või kirjuta selle juhis ja seaded ümber iga sissetuleva kõne jaoks eraldi, lähtudes sinu hallatavas veebikonksus olevast kohandatud loogikast.

Vaikimisi on igale telefoninumbrile ja avaldatavale võtmele määratud staatiline agent. Kui vajad helistajapõhist või külastajapõhist kohandamist — VIP-marsruutimist, sisselogitud kasutaja konteksti, A/B-viibetestimist — lülitu webhooki režiimi ja lase oma serveril otsustada.

Kuidas see toimib

  1. Tellid sündmuse telephony.incoming (telefon) või web.incoming (vidin). Mõlemad on blokeerivad webhookid: ThunderPhone ootab enne kõne jätkamist sinu vastust — telefonikõne puhul kuni 13 sekundit (sh üks uuestikatse) ja vidinaseansi puhul 10 sekundit.
  2. ThunderPhone saadab sulle {call_id, from_number, to_number} (vidina seansid sisaldavad numbrite asemel vidinapõhiseid välju — vaata päringu skeemi).
  3. Sinu server vastab agendi konfiguratsiooniga (viip, hääl, toode, tööriistad). ThunderPhone kasutab seda konfiguratsiooni kõne jaoks.
  4. Varuagent puudub. Kui tagastad {} või vigase konfiguratsiooni või kui päring ebaõnnestub ka pärast selle uuestikatset, lõpetatakse telefonikõne kohe ja salvestatakse end_reason-iga inbound_config_webhook_failed; vidinaseansi päring ebaõnnestub.

1. Seadista webhooki sihtkoht

Telefoninumbrite jaoks telli oma lõpp-punkt sündmusele 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"]
  }'

Vastus sisaldab ühekordset secret-it — salvesta see; kasutad seda allkirja kontrollimiseks.

Vidinaseansside jaoks loo avaldatav võti režiimis mode="webhook", mille sisse on lisatud sinu lõpp-punkti URL:

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"]
  }'

Vidin saadab iga seansi alustamisel sellele URL-ile POST-päringu.

2. Rakenda töötleja

Kolm rusikareeglit:

  • Kontrolli allkirja iga päringu puhul (vt Veebikonksu allkirjade kontrollimine). Ära jäta seda arenduses vahele — tee see üks kord õigesti ja kasuta uuesti.
  • Vasta kiiresti. Telefonikõne esimene katse katkestatakse 10 sekundi järel ja kogu vahetus 13 sekundi järel ning iga sekund on helistaja jaoks vaikus. Tee vajadusel andmebaasipäringuid, kuid ära kutsu järgnevaid LLM-e sünkroonselt — kui soovid dünaamilist viiba genereerimist, arvuta see ette ja vahemällu salvesta.
  • Kasuta selget varuvarianti. Iga ootamatu oleku korral vasta vaikimisi prompti ja voiceiga (või salvestatud agent_idga). Väärtuse {} või veastaatuse tagastamine lõpetab kõne.
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. Vastuse skeem

Vastuse sisu vastab täpselt sissetuleva kõne vastuse skeemile. Levinud väljad:

VäliTüüpKirjeldus
promptstring (nõutav)Agendi süsteemiviip
voicestring (nõutav)Hääl-ID asukohast GET /v1/voices
productstringVaikimisi kasutatakse spark. Eksperimentaalsed tooted on saadaval ainult lubatud loendisse kantud organisatsioonidele.
background_trackstring | nullTaustaheli ID
acknowledgement_prompt_modestringauto või manual (ainult kinnitusega Stormi puhul)
acknowledgement_promptstringNõutav, kui režiim on manual
toolsarrayReasisesed funktsioonitööriistade skeemid — vaata Funktsioonitööriistad

Hoia salvestatud agenti ja edasta muutujaid

Tagasta {"agent_id": 12, "variables": {"name": "Ada"}}, et kasutada selle organisatsiooni salvestatud agenti kõnepõhiste andmetega. Selle viip võib sisaldada {{name}} või {{name|Friend}}. Webhooki muutujad ühendatakse päringutaseme muutujatega; null kasutab kohatäite vaikeväärtust või tühja teksti, kui vaikeväärtust pole määratud. Lõplikud väärtused ja lahendamata nimed kuvatakse kõne üksikasjades ja lõpetamise webhookides. Salvestatud agendi vastused aktsepteerivad ainult agent_id, variables ja timezone. Kui prompt on olemas, kasutab vastus sisemist konfiguratsiooni ja eirab agent_id-d (sealhulgas nulli või mittetäisarvulisi metaandmeid); sisemine viip peab siiski olema kehtiv. Sisemise konfiguratsiooni vastused võivad sisaldada ka variables. Salvestatud agendi vastused kasutavad agendi juurutatud A/B-jaotust nii telefoni- kui ka vidinakõnede puhul ning seejärel renderdavad muutujad. Piirangute ja seansi API toe kohta vaata teemat kõnemuutujad. Blokeeriv konfiguratsioon pärineb pärandtelefoninumbri/organisatsiooni URL-ist või webhookirežiimis vidina võtmest; lõpp-punkti süsteemi sissetulevad sündmused on ainult teavitused.

Määra ajavöönd kõnepõhiselt

Üks häälagent saab vastata kontaktidele eri ajavööndites. Lisa salvestatud agendi või tekstisisese vastuse juurde IANA nimi timezone ning agent ütleb selle kõne puhul kuupäeva ja kellaaja ning pakub aegu selles ajavööndis, sõltumata agendi enda ajavööndist:

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

Saada ajavöönd, mitte ajatempel, variables-is: agendi kell töötab kõne ajal edasi ja edastatud aeg aegub. Väärtust, mis ei ole IANA ajavöönd, eiratakse ning kõne ühendatakse agendi ajavööndis.

Mustrite näited

Sisselogitud kasutaja kontekst

Veebikonksurežiimis vidinates teab külastaja leht juba, kes ta on. Kutsu oma veebikonks välja päringustringi parameetriga, mille vidina SDK edastab (?customer_id=123), ja otsi klient serveripoolel üles.

A/B-juhise kasutuselevõtt

Enne kui selle ise käsitsi lahendad, pane tähele, et ThunderPhone'il on sisseehitatud eksperimentide funktsioon (/dashboard/experiments ja agendiehitaja A/B vahekaart), mis määratleb variandid, jagab liikluse ja võrdleb tulemusi variantide kaupa — veebikonksu pole vaja.

Kui vajad siiski veebikonksupoolset juhtimist: räsi call_id → ämber; serveeri juhist A väärtustele 0..49 ja juhist B väärtustele 50..99. Salvesta, millise ämbri valisid, oma andmebaasi ning korreleeri see hiljem lõpetatud kõne hindega.

Ajapõhine suunamine

Tööajal → „otseabi” agent; väljaspool tööaega → „võta sõnum” agent. Puhtalt lüliti new Date().getUTCHours() põhjal sinu töötlejas.


Järgmised sammud