ThunderPhone 2.0 jau čia.Viską atlikite savarankiškai – nuo 2 ct/min.Skaityti pranešimą

Webhooks

telephony.incoming / web.incoming

Blokuojanti žiniatinklio užklausa, realiuoju laiku nustatanti įeinančio skambučio konfigūraciją.

Kai įeinantis telefono skambutis pasiekia numerį be priskirto agento arba žiniatinklio valdiklio sesija pradedama naudojant viešąjį raktą su mode="webhook", ThunderPhone siunčia blokuojančią telephony.incoming / web.incoming užklausą į jūsų senąjį webhook URL ir iki 10 sekundžių laukia konfigūracijos atsakymo. Naudokite šį apsikeitimą, kad kiekvienam skambučiui dinamiškai pasirinktumėte raginimą, balsą ir įrankius — visą procesą rasite dinaminės skambučio konfigūracijos vadove.

Blokuojantis apsikeitimas neturi atsarginio varianto: jei jūsų apdorotojas grąžina ne 2xx būseną, baigiasi jo skirtasis laikas arba jis grąžina konfigūraciją, kuri nepraeina tikrinimo, skambutis atmetamas (telefono skambutis neprisijungia; valdiklio sesijos užklausa nepavyksta su 502/422). Atsakykite greitai — kol nusprendžiate, skambintojas girdi skambučio signalą.

Užklausos duomenys

Telefono skambučiams (telephony.incoming):

{
  "type": "telephony.incoming",
  "data": {
    "call_id":     987654321,
    "from_number": "+14155550199",
    "to_number":   "+15551234567"
  }
}
LaukasTipasAprašymas
call_idintegerSkambučio ID — nekinta visuose šio skambučio įvykiuose
from_numberstringSkambintojo E.164 numeris
to_numberstringE.164 paskirties numeris (vienas iš jūsų ThunderPhone numerių)

Žiniatinklio valdiklio sesijoms (web.incoming) data identifikuoja įterpimo puslapį, o ne telefono numerius:

{
  "type": "web.incoming",
  "data": {
    "call_id": 987654322,
    "origin_domain": "https://example.com",
    "publishable_key_prefix": "pk_live_a1b2"
  }
}
LaukasTipasAprašymas
call_idintegerSkambučio ID
origin_domainstringValdiklį talpinančio puslapio kilmė
publishable_key_prefixstringPirmieji viešojo rakto, kuris pradėjo sesiją, simboliai
language, primary_languagestringPateikiama, kai valdiklio sesijoje prašoma pakeisti kalbą
voicestringPateikiama, kai valdiklio sesijoje prašoma pakeisti balsą
website_contextstringPateikiama, kai valdiklis perdavė vienos sesijos puslapio kontekstą

Atsakymo schema

Grąžinkite JSON objektą, aprašantį šio skambučio agento konfigūraciją. prompt ir voice yra privalomi; visa kita yra pasirinktinė.

{
  "prompt":  "You are a helpful booking assistant for Acme Restaurant.",
  "voice":   "john",
  "product": "spark",
  "background_track": null,
  "tools":   []
}
LaukasTipasPrivalomaAprašymas
promptstringtaipSisteminė instrukcija, valdanti agentą
voicestringtaipBalso ID iš GET /v1/voices, pvz., john. voice_name priimamas kaip alternatyvus pavadinimas. Nežinomi balsai neatitinka tikrinimo ir skambutis atmetamas
productstringneNumatytoji reikšmė yra spark. Leidžiama: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack
thinking_levelstringneminimal, base (numatytoji reikšmė) arba extra. Storm produktams perrašoma: storm-extra* nustato extra, kiti storm-* nustato base
audio_context_modestringnefull (numatytoji reikšmė) arba reduced
watchdog_enabledbooleanneĮjungti šio skambučio priežiūrą. Numatytoji reikšmė false
additional_audio_contextboolean | nullneĮtraukti kelis paskutinius skambintojo garso pokalbio ėjimus, o ne tik naujausią, taip pagerinant pataisymus ir duomenų, kuriuose daug raidžių ar skaičių, rinkimą, šiek tiek padidinant delsą ir kainą. Numatyta įjungta įeinantiems seansams ir išjungta išeinantiems telefono skambučiams; null palieka numatytąją reikšmę
storm_feedback_modestringnenone, acknowledgement (numatytoji reikšmė) arba tick
languagestringneTrumpinys, skirtas primary_language
primary_languagestringneKalbos kodas, normalizuotas (numatytoji reikšmė en). Neišsprendžiami kodai atmeta skambutį
has_additional_languagesbooleanneNumatytoji reikšmė false
additional_languagesarray of stringnePapildomos kalbos, į kurias agentas gali persijungti
native_voice_switchingbooleanneNumatytoji reikšmė false. Skambučiui persijungus į kitą kalbą, pakeiskite balsą į tai kalbai gimtąjį balsą (atitinkantį lytį), užuot išlaikę sukonfigūruotą balsą
background_trackstring | nullneAplinkos garso ID arba null
acknowledgement_prompt_modestringneauto (numatytoji reikšmė) arba manual (Storm su patvirtinimu produktams)
acknowledgement_promptstringneNaudojama, kai acknowledgement_prompt_mode="manual"
silence_interval_secondsinteger | nullne5–120. Skambintojo tylos sekundės iki pasiteiravimo
silence_max_checkinsinteger | nullne1–10
silence_checkins_enabledbooleanneNumatytoji reikšmė true
connect_tone_enabledbooleanneNumatytoji reikšmė false
voicemail_actionstringneprompt (numatytoji reikšmė), hangup arba message
voicemail_messagestringneNaudojama, kai voicemail_action="message"
agent_namestringneRodomas pavadinimas, pateikiamas valdymo skydeliuose ir valdiklyje
org_namestringneOrganizacijos rodomas pavadinimas agento personai
toolsarrayneĮterptinės funkcijų įrankių schemos (žr. Funkcijų įrankiai)
call_idintegernePasirinktinis užklausos skambučio ID atkartojimas; ignoruojamas

Kadangi prompt ir voice yra privalomi, grąžinus {} arba bet kokį atsakymą, kuris neatitinka tikrinimo, skambutis atmetamas su 422 — šiuo keliu nėra statinio agento atsarginio varianto (numeris arba raktas žiniatinklio kablio režimu neturi priskirto agento).


Atsakymo dydžio apribojimas


Apdorojimo programos pavyzdys

Python (FastAPI)
import hashlib
import hmac
import json
import os
 
from fastapi import FastAPI, HTTPException, Request
 
app = FastAPI()
WEBHOOK_SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]
 
def verify(body: bytes, signature: str) -> bool:
    expected = hmac.new(WEBHOOK_SECRET.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature or "")
 
@app.post("/thunderphone-webhook")
async def webhook(request: Request):
    body = await request.body()
    if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
        raise HTTPException(status_code=401)
 
    event = json.loads(body)
    if event["type"] == "telephony.incoming":
        caller = event["data"]["from_number"]
        prompt = (
            "Greet the caller as a San Francisco local…"
            if caller.startswith("+1415")
            else "You are a friendly customer support agent…"
        )
        return {
            "prompt": prompt,
            "voice": "john",
            "product": "spark",
        }
    if event["type"] == "web.incoming":
        return {
            "prompt": "You are the website's helpful voice assistant…",
            "voice": "john",
            "product": "spark",
        }
    return {}
Node.js (Express)
import crypto from "node:crypto";
import express from "express";
 
const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;
 
function verify(body, signature) {
  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(body)
    .digest("hex");
  return signature &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
 
app.post(
  "/thunderphone-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
      return res.sendStatus(401);
    }
    const event = JSON.parse(req.body.toString("utf8"));
 
    if (event.type === "telephony.incoming" || event.type === "web.incoming") {
      const caller = event.data.from_number || "web";
      const prompt = caller.startsWith("+1415")
        ? "Greet the caller as a San Francisco local…"
        : "You are a friendly customer support agent…";
      return res.json({
        prompt,
        voice: "john",
        product: "spark",
      });
    }
    res.json({});
  },
);

Atsakymas su funkcijų įrankiais

Pridėkite įrankius, kad dirbtinis intelektas pokalbio metu galėtų iškviesti jūsų API:

{
  "prompt":  "You are a booking assistant. Use the available tools to help customers schedule appointments.",
  "voice":   "john",
  "product": "spark",
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "search_appointments",
        "description": "Find available appointment slots",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "service": { "type": "string" }
          },
          "required": ["date"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/search",
        "method": "POST",
        "headers": {
          "X-Api-Key": "your-key"
        }
      }
    }
  ]
}

Produktų pakopų atmintinė

ProduktasDelsaMąstymasPatvirtinimas
sparkMažiausiaPagrindinis
boltMažaPatobulintas
storm-baseVidutinėStiprus
storm-base-with-ackVidutinėStiprusAutomatinė užpildo frazė mąstant
storm-extraDidesnėGilus
storm-extra-with-ackDidesnėGilusAutomatinė užpildo frazė mąstant

Susiję