ThunderPhone 2.0 er lansert.Kom i gang selv – fra 2¢/min.Les mer om lanseringen

Webhooks

telephony.incoming / web.incoming

Blokkerende webhook som former konfigurasjonen for et innkommende anrop i sanntid.

Når et innkommende telefonanrop når et nummer uten en tilordnet stemmeagent, eller en nettwidgetøkt starter med en publiserbar nøkkel i mode="webhook", sender ThunderPhone en blokkerende telephony.incoming / web.incoming-forespørsel til din eldre webhook-URL og venter på et konfigurasjonssvar: opptil 13 sekunder for et telefonanrop, inkludert ett nytt forsøk, og opptil 10 sekunder for en widgetøkt (se Tidsavbrudd og nye forsøk). Bruk denne utvekslingen til å velge prompt, stemme og verktøy dynamisk for hvert anrop — se veiledningen for dynamisk samtalekonfigurasjon for det fullstendige mønsteret.

Tidsavbrudd og nye forsøk

Svar raskt: innringeren venter på linjen mens du avgjør.

For en telefonsamtale (telephony.incoming):

  • Det første forsøket kan ta opptil 10 sekunder.
  • Hvis det får tidsavbrudd, ikke kan koble til eller får et 5xx-, 408- eller 429-svar, prøver ThunderPhone én gang til. Det nye forsøket får det som gjenstår av et 13-sekunders budsjett for hele utvekslingen: omtrent 3 sekunder etter et første forsøk som fikk tidsavbrudd, og nesten alle 13 etter en rask feil. Det gjøres ikke et nytt forsøk hvis det ville gjenstått mindre enn 2 sekunder.
  • Ethvert annet 4xx-svar, et svar over størrelsesgrensen, eller et 2xx-svar med en brødtekst som ikke er en gyldig konfigurasjon, er endelig og prøves ikke på nytt.
  • Begge forsøkene sender den samme brødteksten, den samme X-ThunderPhone-Signature-headeren og den samme X-ThunderPhone-Idempotency-Key-headeren (telephony-incoming-<call_id>), slik at en håndterer med sideeffekter kan gjenkjenne det nye forsøket.

Det finnes ingen reserve-stemmeagent. Hvis ingen brukbar konfigurasjon kommer frem, blir samtalen avsluttet med én gang i stedet for å la innringeren vente på en stille linje. Den vises i samtalehistorikken som en mislykket, ikke-fakturert samtale med end_reason inbound_config_webhook_failed, og den vanlige telephony.complete-hendelsen sendes.

En widgetøkt (web.incoming) får ett enkelt forsøk på opptil 10 sekunder. Hvis det mislykkes, mislykkes øktforespørselen med 502 eller 422.

Forespørselsnyttelast

For telefonanrop (telephony.incoming):

{
  "type": "telephony.incoming",
  "data": {
    "call_id":     987654321,
    "from_number": "+14155550199",
    "to_number":   "+15551234567"
  }
}
FeltTypeBeskrivelse
call_idintegerAnrops-ID — stabil på tvers av alle hendelser for dette anropet
from_numberstringE.164-nummeret til innringeren
to_numberstringE.164-destinasjon (ett av ThunderPhone-numrene dine)

For webwidget-økter (web.incoming) identifiserer data innbyggingssiden i stedet for telefonnumre:

{
  "type": "web.incoming",
  "data": {
    "call_id": 987654322,
    "origin_domain": "https://example.com",
    "publishable_key_prefix": "pk_live_a1b2"
  }
}
FeltTypeBeskrivelse
call_idheltallAnrops-ID
origin_domainstrengSidens opphav som er vert for widgeten, slik nettleseren sendte det. En klient som ikke er en nettleser, kan sende en hvilken som helst verdi, så ikke behandle den som bevis på hvor forespørselen kom fra
publishable_key_prefixstrengDe første tegnene i den publiserbare nøkkelen som åpnet økten
language, primary_languagestrengFinnes når widgetøkten ba om en språkoverstyring
voicestrengFinnes når widgetøkten ba om en stemmeoverstyring
website_contextstrengFinnes når widgeten sendte sidekontekst per økt

Overstyringsfeltene (language, voice, website_context og eventuelle nettleser-variables) kommer bare når den publiserbare nøkkelen tillater dem i sine nettleseroverstyringer. En øktforespørsel som inneholder en overstyring nøkkelen ikke tillater, avvises før denne webhooken kalles.


Svarskjema

Returner et JSON-objekt som beskriver stemmeagentkonfigurasjonen for dette anropet. prompt og voice er påkrevd; alt annet er valgfritt.

{
  "prompt":  "You are a helpful booking assistant for Acme Restaurant.",
  "voice":   "john",
  "product": "spark",
  "background_track": null,
  "tools":   []
}
FeltTypePåkrevdBeskrivelse
promptstrengjaSysteminstruks som styrer agenten
voicestrengjaStemme-ID fra GET /v1/voices, for eksempel john. voice_name godtas som et alias. Ukjente stemmer feiler valideringen og avviser samtalen
productstrengneiStandard er spark. Tillatt: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack
thinking_levelstrengneiminimal, base (standard) eller extra. Overstyres for Storm-produkter: storm-extra* tvinger extra, andre storm-* tvinger base
audio_context_modestrengneifull (standard) eller reduced
watchdog_enabledboolskneiAktiver overvåking for denne samtalen. Standard er false
additional_audio_contextboolsk | nullneiTa med de siste rundene med innringerlyd i stedet for bare den nyeste runden, noe som forbedrer rettelser og datainnsamling med mye staving/tall, med en liten økning i forsinkelse/kostnad. Er på som standard for innkommende økter og av for utgående telefonsamtaler; null beholder standardverdien
storm_feedback_modestrengneinone, acknowledgement (standard) eller tick
languagestrengneiKortform for primary_language
primary_languagestrengneiSpråkkode, normalisert (standard en). Koder som ikke kan løses, avviser samtalen
has_additional_languagesboolskneiStandard er false
additional_languagesmatrise av strengerneiEkstra språk agenten kan bytte til
native_voice_switchingboolskneiStandard er false. Når samtalen bytter til et annet språk, bytt til en stemme som har språket som morsmål (matchet etter kjønn) i stedet for å beholde den konfigurerte stemmen
language_switchingstreng | nullneiask_first (standard) eller follow_caller; null er det samme som ask_first. Angir hvordan en flerspråklig agent håndterer at den andre personen snakker et annet av språkene dens. ask_first bytter straks når personen ber om språket eller sier en hel setning på det, og spør om dere skal fortsette på det etter noe kort, som et «ja». follow_caller bytter til ethvert konfigurert språk personen snakker, selv bare ett ord. Gjelder bare når additional_languages er angitt
background_trackstreng | nullneiID for bakgrunnslyd eller null
acknowledgement_prompt_modestrengneiauto (standard) eller manual (Storm-with-ack-produkter)
acknowledgement_promptstrengneiBrukes når acknowledgement_prompt_mode="manual"
silence_interval_secondsheltall | nullnei5–120. Sekunder med stillhet fra innringeren før en oppfølging
silence_max_checkinsheltall | nullnei1–10
silence_checkins_enabledboolskneiStandard er true
connect_tone_enabledboolskneiStandard er false
pronunciation_dictsboolsk | nullneiStandard er false; null er det samme som false. Når verdien er true, bruker samtalens Cartesia-tale ThunderPhones uttaleordbok for samtalens språk, der en finnes. Fungerer for telefon- og widget-samtaler. Gjelder bare ThunderPhones egne Cartesia-stemmer, ikke stemmer på din egen Cartesia API-nøkkel. Brukes ikke med agent_id, der den lagrede agentens innstillinger gjelder
voicemail_actionstrengneiprompt (standard), hangup eller message
voicemail_messagestrengneiBrukes når voicemail_action="message"
agent_namestrengneiVisningsnavn som rapporteres til instrumentpaneler og widgeten
org_namestrengneiOrganisasjonens visningsnavn for agentens persona
toolsmatriseneiInnebygde skjemaer for funksjonsverktøy (se Funksjonsverktøy)
transfer_destinationsmatrise av objekter | nullneiOpptil 50 {name, number}-oppføringer som denne samtalen kan overføres til, validert på samme måte som en agents overføringsnumre. Agenten overfører etter navn og bare til disse; [] betyr ingen overføringer. Utelat feltet eller send null for å la agenten overføre til et nummer den velger
timezonestrengneiIANA-tidssone for denne samtalen, for eksempel America/Chicago. Agenten oppgir datoen og klokkeslettet i denne, foran agentens egen tidssone. Tillatt også sammen med agent_id. Verdier som ikke er IANA-tidssoner, ignoreres. Se Angi tidssone per samtale
call_idheltallneiValgfritt ekko av forespørselens samtale-ID; ignoreres

Fordi prompt og voice er obligatoriske, avviser retur av {} eller et svar som ikke består valideringen anropet: en telefonsamtale avsluttes som beskrevet i Tidsavbrudd og nye forsøk, og en forespørsel om widgetøkt mislykkes med 422. Det finnes ingen reserve for statisk agent på denne banen (et nummer eller en nøkkel i webhook-modus har ingen tildelt agent).


Grense for responsstørrelse


Eksempelbehandler

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({});
  },
);

Svar med funksjonsverktøy

Legg ved verktøy slik at AI-en kan kalle API-ene dine midt i samtalen:

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

Hurtigoversikt over produktnivåer

ProduktForsinkelseResonneringBekreftelse
sparkLavestGrunnleggende—
boltLavForbedret—
storm-baseMiddelsSterk—
storm-base-with-ackMiddelsSterkAutomatisk utfylling mens den tenker
storm-extraHøyereDyp—
storm-extra-with-ackHøyereDypAutomatisk utfylling mens den tenker

Relatert