Επισκόπηση Webhook
Το ThunderPhone στέλνει αιτήματα HTTP POST στον διακομιστή σας όταν
συμβαίνουν ενέργειες κατά τη διάρκεια μιας κλήσης — ξεκινά μια εισερχόμενη κλήση, ολοκληρώνεται μια κλήση, ολοκληρώνεται μια εκτέλεση αξιολόγησης, ενεργοποιείται μια ειδοποίηση κ.ο.κ. Υπάρχουν δύο μοντέλα παράδοσης:
Πολλαπλά URL, μυστικά ανά τελικό σημείο, φίλτρα συμβάντων ανά τελικό σημείο
και αυτόματες επαναλήψεις.
Διαχείριση μέσω GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints.
Ένα URL ανά οργανισμό. Περιλαμβάνει τα συμβάντα κύκλου ζωής κλήσης, συμπεριλαμβανομένων των
μπλοκαριστικών ανταλλαγών ρυθμίσεων. Διαχείριση στο GET/PUT /v1/webhook.
Και οι δέκα τύποι συμβάντων στον κατάλογο συμβάντων
παραδίδονται μέσω τελικών σημείων webhook. Τα έξι συμβάντα κύκλου ζωής κλήσης
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) αποστέλλονται επίσης στο
webhook παλαιού τύπου με ένα URL — αν έχετε και ένα URL παλαιού τύπου και ένα
αντίστοιχο τελικό σημείο, λαμβάνετε το συμβάν και από τις δύο διαδρομές. Η
μπλοκαριστική συμπεριφορά (η ανταλλαγή ρυθμίσεων
telephony.incoming / web.incoming και η
δρομολόγηση εργαλείων σε λειτουργία webhook)
υπάρχει αποκλειστικά στη διαδρομή παλαιού τύπου· κάθε παράδοση σε τελικό σημείο είναι
ειδοποίηση χωρίς αναμονή.
Μορφή ωφέλιμου φορτίου
Οι παραδόσεις σε τελικά σημεία είναι ένα αντικείμενο JSON με data, event_id και
type:
{
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
},
"event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
"type": "telephony.incoming"
}
Το event_id είναι μοναδικό για κάθε εκπεμπόμενο συμβάν. Είναι ίδιο σε όλες τις επαναλήψεις
και σε κάθε τελικό σημείο που λαμβάνει το συμβάν — κάντε αποδιπλοποίηση βάσει αυτού.
Το webhook παλαιού τύπου με ένα URL στέλνει τα ίδια type και data, αλλά
χωρίς event_id:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}
Στο δίκτυο, κάθε σώμα σειριοποιείται κανονικά — τα κλειδιά ταξινομούνται αλφαβητικά, χωρίς κενά, σε UTF-8. Τα παραδείγματα με μορφοποίηση σε αυτές τις τεκμηριώσεις παρέχονται μόνο για αναγνωσιμότητα.
Δείτε τον Κατάλογο συμβάντων για την πλήρη λίστα τύπων συμβάντων και πεδίων ωφέλιμου φορτίου.
Επαλήθευση υπογραφής
Κάθε αίτημα περιλαμβάνει υπογραφή HMAC-SHA256 για το ακατέργαστο σώμα
αιτήματος στην κεφαλίδα X-ThunderPhone-Signature. Το κλειδί υπογραφής είναι το
secret του τελικού σημείου (ή το secret του webhook σε επίπεδο οργανισμού για
παλαιότερες παραδόσεις).
Βήματα
- Διαβάστε το ακατέργαστο σώμα αιτήματος πριν από οποιαδήποτε ανάλυση.
- Υπολογίστε
hmac_sha256(secret, body).hexdigest(). - Συγκρίνετε σε σταθερό χρόνο με την κεφαλίδα
X-ThunderPhone-Signature.
Υπογράφουμε ακριβώς τα byte που μεταδίδουμε και αυτά τα byte είναι η κανονική σειριοποίηση JSON (ταξινομημένα κλειδιά, συμπαγείς διαχωριστές). Επομένως, η επαλήθευση με βάση το ακατέργαστο σώμα λειτουργεί πάντα — και αν το πλαίσιο εργασίας σας παρέχει μόνο αναλυμένο JSON, η επανασειριοποίησή του με ταξινομημένα κλειδιά και συμπαγείς διαχωριστές παράγει πανομοιότυπα byte. Και οι δύο μέθοδοι καλύπτονται στον οδηγό επαλήθευσης.
import hmac
import hashlib
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature or "")
# Example Flask handler
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/thunderphone-webhook")
def handle():
body = request.get_data()
sig = request.headers.get("X-ThunderPhone-Signature", "")
if not verify_signature(body, sig, WEBHOOK_SECRET):
abort(401)
event = request.get_json()
# dispatch on event["type"] …
return "", 204
import crypto from "node:crypto";
import express from "express";
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
if (!signature || expected.length !== signature.length) return false;
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature),
);
}
const app = express();
app.post(
"/thunderphone-webhook",
express.raw({ type: "application/json" }),
(req, res) => {
const sig = req.header("X-ThunderPhone-Signature") || "";
if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
// dispatch on event.type …
res.sendStatus(204);
},
);
Σημασιολογία παράδοσης
Αυτή η σημασιολογία εφαρμόζεται στις παραδόσεις σε σημεία τερματισμού. Το παλαιού τύπου webhook με ένα URL πραγματοποιεί μία μόνο σύγχρονη προσπάθεια χωρίς επαναλήψεις.
Επαναλήψεις
Κάθε συμβάν επιχειρείται μία φορά άμεσα. Κάθε απόκριση 2xx
επιβεβαιώνει την παράδοση. Σε κάθε άλλη έκβαση (εκτός 2xx,
σφάλμα σύνδεσης, χρονικό όριο) επαναλαμβάνουμε στις 1 λεπτό, 5 λεπτά, 30 λεπτά, 2 ώρες, 6 ώρες,
12 ώρες και 24 ώρες μετά την πρώτη προσπάθεια — 8 προσπάθειες σε διάστημα
24 ωρών. Αν αποτύχουν όλες οι προσπάθειες, η παράδοση διακόπτεται και το σημείο τερματισμού
επισημαίνεται με status="failing" στα
σημεία τερματισμού webhook. Επιστρέψτε 2xx μόλις
το ωφέλιμο φορτίο γίνει δεκτό με μόνιμο τρόπο· επεξεργαστείτε το ασύγχρονα.
Σειρά
Η σειρά παράδοσης καταβάλλει τη βέλτιστη δυνατή προσπάθεια. Στην πράξη παραδίδουμε με τη
σειρά με την οποία εκπέμπονται τα συμβάντα, αλλά οι επαναλήψεις μπορούν να αλλάξουν τη σειρά σε περίπτωση αποτυχίας.
Να εξαλείφετε πάντα τα διπλότυπα και να συμφωνείτε τα δεδομένα βάσει call_id / αναγνωριστικού αντικειμένου.
Διπλότυπα
Η παράδοση είναι τουλάχιστον μία φορά: μια επανάληψη μετά από απόκριση που δεν
λάβαμε ποτέ μπορεί να δημιουργήσει διπλότυπο συμβάν. Κάθε επανάληψη περιλαμβάνει το ίδιο
event_id, επομένως αποθηκεύστε τα επεξεργασμένα αναγνωριστικά και παραλείψτε τις επαναλήψεις. Το event_id
είναι επίσης κοινό μεταξύ σημείων τερματισμού — δύο σημεία τερματισμού που έχουν εγγραφεί στο
ίδιο συμβάν λαμβάνουν το ίδιο event_id.
Χρονικά όρια
Οι παραδόσεις σε σημεία τερματισμού έχουν χρονικό όριο 30 δευτ. ανά προσπάθεια. Στη
διαδρομή παλαιού τύπου, τα αιτήματα αποκλεισμού που καθοδηγούν τη συμπεριφορά ζωντανών κλήσεων — η
ανταλλαγή ρυθμίσεων telephony.incoming / web.incoming —
λήγουν μετά από 10 δευτ., αλλά μια αργή απόκριση καθυστερεί την απάντηση της κλήσης,
επομένως επιδιώξτε να απαντάτε μέσα σε λίγα δευτερόλεπτα. Η αποστολή εργαλείων σε λειτουργία webhook επιτρέπει 20 δευτ.
IP προέλευσης
Τα εξερχόμενα webhook προέρχονται από το εύρος IP cloud του ThunderPhone. Αν το τείχος προστασίας σας απαιτεί λίστα επιτρεπόμενων διευθύνσεων, επικοινωνήστε με την υποστήριξη και θα μοιραστούμε τα τρέχοντα εύρη.
Επιλογή μεταξύ webhook παλαιού τύπου και webhook βάσει σημείων τερματισμού
| Δυνατότητα | Παλαιού τύπου (/v1/webhook) | Σημεία τερματισμού (/v1/developer/webhook-endpoints) |
|---|---|---|
| Αριθμός URL | 1 ανά οργανισμό | Πολλά ανά οργανισμό |
| Κάλυψη συμβάντων | Μόνο telephony.* / web.* | Και οι 10 τύποι συμβάντων |
| Φίλτρο συμβάντων | — | Ανά σημείο τερματισμού |
| Επαναλήψεις | Καμία | 8 προσπάθειες σε 24 ώρες |
| Περιτύλιγμα | type + data | type + data + event_id |
| Περιστροφή μυστικού | Αντικαθιστά το μοναδικό μυστικό | Μυστικό ανά σημείο τερματισμού |
| Απενεργοποίηση χωρίς διαγραφή | — | status=disabled |
| Ορατότητα κατάστασης | — | active / disabled / failing |
| Ανταλλαγή ρυθμίσεων αποκλεισμού | Ναι (telephony.incoming / web.incoming) | Ποτέ — μόνο ειδοποιήσεις |
| Κατάλληλο για | Δυναμική ρύθμιση κλήσεων | Κατανάλωση συμβάντων στην παραγωγή |
Οι νέες ενσωματώσεις θα πρέπει να καταναλώνουν συμβάντα μέσω webhook βάσει σημείων τερματισμού. Διατηρήστε (ή προσθέστε) ένα URL παλαιού τύπου μόνο αν ρυθμίζετε κλήσεις δυναμικά κατά τη στιγμή της απάντησης ή χρησιμοποιείτε αποστολή εργαλείων σε λειτουργία webhook — αυτές οι ανταλλαγές αιτήματος/απόκρισης εκτελούνται μόνο στη διαδρομή παλαιού τύπου.
Σχετικά
Όλοι οι τύποι συμβάντων και τα ωφέλιμα φορτία τους.
Διαχειριστείτε πολλά σημεία τερματισμού, φίλτρα συμβάντων και μυστικά.
Το αίτημα αποκλεισμού στο οποίο πρέπει να απαντήσει ο διακομιστής σας για να ρυθμίσει κλήσεις.
Ωφέλιμο φορτίο μετά την κλήση με απομαγνητοφώνηση, εγγραφή και μετρήσεις.