Το ThunderPhone 2.0 είναι εδώ.Ξεκινήστε μόνοι σας, από 2¢/λεπτό.Διαβάστε την ανακοίνωση

Webhooks

telephony.incoming / web.incoming

Webhook αποκλεισμού που διαμορφώνει τη ρύθμιση μιας εισερχόμενης κλήσης σε πραγματικό χρόνο.

Όταν μια εισερχόμενη τηλεφωνική κλήση φτάνει σε έναν αριθμό χωρίς ανατεθειμένο πράκτορα, ή όταν ξεκινά μια συνεδρία γραφικού στοιχείου ιστού με ένα δημοσιεύσιμο κλειδί σε mode="webhook", το ThunderPhone στέλνει ένα δεσμευτικό αίτημα telephony.incoming / web.incoming στο παλαιό URL webhook σας και περιμένει έως 10 δευτερόλεπτα για μια απάντηση διαμόρφωσης. Χρησιμοποιήστε αυτή την ανταλλαγή για να επιλέγετε δυναμικά ένα prompt, φωνή και εργαλεία ανά κλήση — δείτε τον οδηγό δυναμικής διαμόρφωσης κλήσεων για την ολοκληρωμένη ροή.

Η δεσμευτική ανταλλαγή δεν διαθέτει εναλλακτική: αν ο χειριστής σας επιστρέψει κατάσταση εκτός 2xx, λήξει το χρονικό όριο ή επιστρέψει διαμόρφωση που αποτυγχάνει στην επικύρωση, η κλήση απορρίπτεται (η τηλεφωνική κλήση δεν συνδέεται· το αίτημα συνεδρίας του γραφικού στοιχείου αποτυγχάνει με 502/422). Απαντήστε γρήγορα — ο καλών ακούει τόνο αναμονής όσο αποφασίζετε.

Ωφέλιμο φορτίο αιτήματος

Για τηλεφωνικές κλήσεις (telephony.incoming):

{
  "type": "telephony.incoming",
  "data": {
    "call_id":     987654321,
    "from_number": "+14155550199",
    "to_number":   "+15551234567"
  }
}
ΠεδίοΤύποςΠεριγραφή
call_idintegerID κλήσης — σταθερό σε όλα τα συμβάντα αυτής της κλήσης
from_numberstringΑριθμός καλούντος E.164
to_numberstringΠροορισμός E.164 (ένας από τους αριθμούς ThunderPhone σας)

Για συνεδρίες γραφικού στοιχείου ιστού (web.incoming), το data αναγνωρίζει τη σελίδα ενσωμάτωσης αντί για τηλεφωνικούς αριθμούς:

{
  "type": "web.incoming",
  "data": {
    "call_id": 987654322,
    "origin_domain": "https://example.com",
    "publishable_key_prefix": "pk_live_a1b2"
  }
}
ΠεδίοΤύποςΠεριγραφή
call_idintegerID κλήσης
origin_domainstringΗ προέλευση της σελίδας που φιλοξενεί το γραφικό στοιχείο
publishable_key_prefixstringΠρώτοι χαρακτήρες του δημοσιεύσιμου κλειδιού που άνοιξε τη συνεδρία
language, primary_languagestringΠαρόν όταν η συνεδρία γραφικού στοιχείου ζήτησε παράκαμψη γλώσσας
voicestringΠαρόν όταν η συνεδρία γραφικού στοιχείου ζήτησε παράκαμψη φωνής
website_contextstringΠαρόν όταν το γραφικό στοιχείο πέρασε περιεχόμενο σελίδας ανά συνεδρία

Σχήμα απόκρισης

Επιστρέψτε ένα αντικείμενο JSON που περιγράφει τη διαμόρφωση του πράκτορα για αυτή την κλήση. Τα prompt και voice είναι υποχρεωτικά· όλα τα υπόλοιπα είναι προαιρετικά.

{
  "prompt":  "You are a helpful booking assistant for Acme Restaurant.",
  "voice":   "john",
  "product": "spark",
  "background_track": null,
  "tools":   []
}
ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
promptstringναιΠροτροπή συστήματος που καθοδηγεί τον πράκτορα
voicestringναιΑναγνωριστικό φωνής από το GET /v1/voices, π.χ. john. Το voice_name γίνεται δεκτό ως ψευδώνυμο. Άγνωστες φωνές αποτυγχάνουν στην επικύρωση και απορρίπτουν την κλήση
productstringόχιΠροεπιλογή: spark. Επιτρεπόμενα: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack
thinking_levelstringόχιminimal, base (προεπιλογή) ή extra. Παρακάμπτεται για προϊόντα Storm: το storm-extra* επιβάλλει extra, ενώ τα άλλα storm-* επιβάλλουν base
audio_context_modestringόχιfull (προεπιλογή) ή reduced
watchdog_enabledbooleanόχιΕνεργοποίηση επιτήρησης για αυτή την κλήση. Προεπιλογή: false
additional_audio_contextboolean | nullόχιΣυμπεριλάβετε τις τελευταίες λίγες εναλλαγές ήχου του καλούντος αντί μόνο της πιο πρόσφατης, βελτιώνοντας τις διορθώσεις και τη συλλογή δεδομένων με πολλά ορθογραφικά στοιχεία ή αριθμούς, με μικρή επιβάρυνση καθυστέρησης/κόστους. Ενεργοποιείται από προεπιλογή για εισερχόμενες συνεδρίες και απενεργοποιείται για εξερχόμενες τηλεφωνικές κλήσεις· το null διατηρεί την προεπιλογή
storm_feedback_modestringόχιnone, acknowledgement (προεπιλογή) ή tick
languagestringόχιΣυντομογραφία για το primary_language
primary_languagestringόχιΚωδικός γλώσσας, κανονικοποιημένος (προεπιλογή en). Κωδικοί που δεν μπορούν να επιλυθούν απορρίπτουν την κλήση
has_additional_languagesbooleanόχιΠροεπιλογή: false
additional_languagesarray of stringόχιΕπιπλέον γλώσσες στις οποίες μπορεί να μεταβεί ο πράκτορας
native_voice_switchingbooleanόχιΠροεπιλογή: false. Όταν η κλήση μεταβαίνει σε άλλη γλώσσα, αλλάζει σε φωνή μητρική σε εκείνη τη γλώσσα (αντιστοιχισμένη κατά φύλο), αντί να διατηρεί τη διαμορφωμένη φωνή
background_trackstring | nullόχιΑναγνωριστικό ήχου περιβάλλοντος ή null
acknowledgement_prompt_modestringόχιauto (προεπιλογή) ή manual (προϊόντα Storm-with-ack)
acknowledgement_promptstringόχιΧρησιμοποιείται όταν acknowledgement_prompt_mode="manual"
silence_interval_secondsinteger | nullόχι5–120. Δευτερόλεπτα σιωπής του καλούντος πριν από έλεγχο
silence_max_checkinsinteger | nullόχι1–10
silence_checkins_enabledbooleanόχιΠροεπιλογή: true
connect_tone_enabledbooleanόχιΠροεπιλογή: false
voicemail_actionstringόχιprompt (προεπιλογή), hangup ή message
voicemail_messagestringόχιΧρησιμοποιείται όταν voicemail_action="message"
agent_namestringόχιΕμφανιζόμενο όνομα που αναφέρεται στους πίνακες ελέγχου και στο γραφικό στοιχείο
org_namestringόχιΕμφανιζόμενο όνομα οργανισμού για την περσόνα του πράκτορα
toolsarrayόχιΕνσωματωμένα σχήματα εργαλείων συναρτήσεων (δείτε Εργαλεία Συναρτήσεων)
call_idintegerόχιΠροαιρετική επανάληψη του αναγνωριστικού κλήσης του αιτήματος· αγνοείται

Επειδή τα prompt και voice είναι υποχρεωτικά, η επιστροφή {} ή οποιασδήποτε απόκρισης που αποτυγχάνει στην επικύρωση απορρίπτει την κλήση με 422 — δεν υπάρχει εναλλακτική λύση στατικού πράκτορα σε αυτή τη διαδρομή (ένας αριθμός ή κλειδί σε λειτουργία webhook δεν έχει εκχωρημένο πράκτορα).


Όριο μεγέθους απόκρισης


Παράδειγμα χειριστή

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

Απόκριση με εργαλεία συναρτήσεων

Επισυνάψτε εργαλεία ώστε ο AI πράκτορας να μπορεί να καλεί τα 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"
        }
      }
    }
  ]
}

Συνοπτικός οδηγός επιπέδων προϊόντος

ΠροϊόνΚαθυστέρησηΣυλλογισμόςΕπιβεβαίωση
sparkΗ χαμηλότερηΒασικός
boltΧαμηλήΒελτιωμένος
storm-baseΜέτριαΙσχυρός
storm-base-with-ackΜέτριαΙσχυρόςΑυτόματο συμπλήρωμα κατά τη σκέψη
storm-extraΥψηλότερηΒαθύς
storm-extra-with-ackΥψηλότερηΒαθύςΑυτόματο συμπλήρωμα κατά τη σκέψη

Σχετικά