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

Webhooks

Επισκόπηση Webhooks

Πώς το ThunderPhone παραδίδει συμβάντα σε πραγματικό χρόνο, πώς να επαληθεύετε υπογραφές και πώς συγκρίνονται τα παλαιού τύπου και τα βασισμένα σε endpoint μοντέλα παράδοσης.

Το ThunderPhone στέλνει αιτήματα HTTP POST στον διακομιστή σας όταν συμβαίνουν ενέργειες κατά τη διάρκεια μιας κλήσης — ξεκινά μια εισερχόμενη κλήση, ολοκληρώνεται μια κλήση, ολοκληρώνεται μια εκτέλεση αξιολόγησης, ενεργοποιείται μια ειδοποίηση και ούτω καθεξής. Υπάρχουν δύο μοντέλα παράδοσης:

Όλοι οι τύποι συμβάντων που αναφέρονται στον κατάλογο συμβάντων παραδίδονται μέσω τελικών σημείων webhook. Τα έξι συμβάντα κύκλου ζωής κλήσης (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) αποστέλλονται επίσης στο webhook παλαιού τύπου με ένα URL — αν έχετε και URL παλαιού τύπου και αντίστοιχο τελικό σημείο, λαμβάνετε το συμβάν και από τις δύο διαδρομές. Η δεσμευτική συμπεριφορά (η ανταλλαγή διαμόρφωσης telephony.incoming / web.incoming και η δρομολόγηση εργαλείων σε λειτουργία webhook) υπάρχει αποκλειστικά στη διαδρομή παλαιού τύπου· κάθε παράδοση σε τελικό σημείο είναι ειδοποίηση αποστολής χωρίς αναμονή.

Μορφή payload

Οι παραδόσεις σε τελικά σημεία είναι ένα αντικείμενο 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. Τα παραδείγματα με μορφοποίηση σε πολλές γραμμές σε αυτή την τεκμηρίωση προορίζονται μόνο για αναγνωσιμότητα.

Δείτε τον Κατάλογο συμβάντων για την πλήρη λίστα τύπων συμβάντων και πεδίων payload.

Επαλήθευση υπογραφής

Κάθε αίτημα φέρει δύο υπογραφές, και οι δύο HMAC-SHA256 με κλειδί το secret του endpoint (ή το secret του webhook σε επίπεδο οργανισμού για παλαιές παραδόσεις):

  • Το X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> υπογράφει τη χρονική σήμανση, τη μέθοδο, τη διαδρομή και το ερώτημα, καθώς και το ακατέργαστο σώμα. Επαληθεύστε αυτήν και απορρίψτε αιτήματα των οποίων το t απέχει περισσότερο από 5 λεπτά από το ρολόι σας, ώστε ένα υποκλαπέν αίτημα να μην μπορεί να επαναληφθεί αργότερα. Οι επαναλήψεις υπογράφονται ξανά όταν αποστέλλονται.
  • Το X-ThunderPhone-Signature υπογράφει μόνο το ακατέργαστο σώμα. Εξακολουθεί να αποστέλλεται, χωρίς αλλαγές, ώστε οι υπάρχοντες επαληθευτές να συνεχίσουν να λειτουργούν.

Βήματα

  1. Διαβάστε την κεφαλίδα, τη μέθοδο, την ακατέργαστη διαδρομή και το ερώτημα, και το ακατέργαστο σώμα πριν από οποιαδήποτε ανάλυση.
  2. Υπολογίστε το δεκαεξαδικό HMAC-SHA256 του <t>\n<METHOD>\n<path and query>\n<body> με το μυστικό σας.
  3. Απορρίψτε το αίτημα αν το t απέχει περισσότερο από 300 δευτερόλεπτα ή αν το αποτέλεσμα δεν αντιστοιχεί στο v1 σε σύγκριση σταθερού χρόνου.

Τα σώματα είναι η κανονική σειριοποίηση JSON (ταξινομημένα κλειδιά, συμπαγείς διαχωριστές) και υπογράφουμε ακριβώς τις οκτάδες που μεταδίδουμε. Ο οδηγός επαλήθευσης περιλαμβάνει την ακριβή υπογεγραμμένη συμβολοσειρά, ένα αναλυτικό παράδειγμα, κώδικα χωρίς το SDK και την παλαιότερη κεφαλίδα.

Python (Flask)
from flask import Flask, abort, request
from thunderphone import verify_signature
 
app = Flask(__name__)
 
@app.post("/thunderphone-webhook")
def handle():
    query = request.query_string.decode()
    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=WEBHOOK_SECRET,
        method=request.method,
        path=request.path + (f"?{query}" if query else ""),
        body=request.get_data(),  # raw bytes
    ):
        abort(401)
    event = request.get_json()
    # dispatch on event["type"] …
    return "", 204
Node.js (Express)
import express from "express";
import { verifySignature } from "@thunderphone/sdk";
 
const app = express();
app.post(
  "/thunderphone-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const ok = verifySignature({
      header: req.header("X-ThunderPhone-Signature-V2"),
      secret: process.env.WEBHOOK_SECRET,
      method: req.method,
      path: req.originalUrl,
      body: req.body,
    });
    if (!ok) return res.sendStatus(401);
    const event = JSON.parse(req.body.toString("utf8"));
    // dispatch on event.type …
    res.sendStatus(204);
  },
);

Σημασιολογία παράδοσης

Αυτές οι σημασιολογικές αρχές ισχύουν για παραδόσεις σε τελικά σημεία. Η παλαιού τύπου διαδικτυακή ειδοποίηση μίας διεύθυνσης URL είναι μία σύγχρονη προσπάθεια χωρίς επαναλήψεις, εκτός από την ανταλλαγή ρυθμίσεων για τηλεφωνικές κλήσεις telephony.incoming, η οποία επαναλαμβάνεται μία φορά.

Επαναλήψεις

Κάθε συμβάν επιχειρείται αμέσως μία φορά. Κάθε απόκριση 2xx επιβεβαιώνει την παράδοση. Σε κάθε άλλη έκβαση (όχι 2xx, σφάλμα σύνδεσης, χρονικό όριο), επαναλαμβάνουμε την προσπάθεια 1 λεπτό, 5 λεπτά, 30 λεπτά, 2 ώρες, 6 ώρες, 12 ώρες και 24 ώρες μετά την πρώτη προσπάθεια — 8 προσπάθειες σε διάστημα 24 ωρών. Αν αποτύχει κάθε προσπάθεια, η παράδοση σταματά και το τελικό σημείο επισημαίνεται με status="failing" στα τελικά σημεία διαδικτυακών ειδοποιήσεων· στέλνουμε μήνυμα ηλεκτρονικού ταχυδρομείου στους κατόχους και τους διαχειριστές του οργανισμού σας και το εμφανίζουμε στον πίνακα ελέγχου. Επιστρέψτε 2xx μόλις το ωφέλιμο φορτίο γίνει δεκτό με ανθεκτικό τρόπο· επεξεργαστείτε το ασύγχρονα. Οι δοκιμαστικές αποστολές από το API δοκιμών του τελικού σημείου λαμβάνουν μία επανάληψη περίπου ένα λεπτό μετά την πρώτη προσπάθεια και δεν αλλάζουν ποτέ την κατάσταση του τελικού σημείου.

Σειρά

Η σειρά παράδοσης είναι κατά το δυνατόν εγγυημένη. Στην πράξη παραδίδουμε με τη σειρά που εκπέμπονται τα συμβάντα, αλλά οι επαναλήψεις μπορεί να αλλάξουν τη σειρά σε περίπτωση αποτυχίας. Πάντα να εξαλείφετε διπλότυπα και να συμφωνείτε δεδομένα βάσει call_id / αναγνωριστικού αντικειμένου.

Διπλότυπα

Η παράδοση είναι τουλάχιστον μία φορά: μια επανάληψη μετά από απόκριση που δεν λάβαμε ποτέ μπορεί να δημιουργήσει διπλότυπο συμβάν. Κάθε επανάληψη φέρει το ίδιο event_id, επομένως αποθηκεύστε τα αναγνωριστικά που επεξεργαστήκατε και παραλείψτε τις επαναλήψεις. Το event_id κοινοποιείται επίσης μεταξύ τελικών σημείων — δύο τελικά σημεία που έχουν εγγραφεί στο ίδιο συμβάν λαμβάνουν το ίδιο event_id.

Χρονικά όρια

Οι παραδόσεις σε τελικά σημεία έχουν χρονικό όριο 30 δευτερολέπτων ανά προσπάθεια. Στην παλαιού τύπου διαδρομή, τα αιτήματα αποκλεισμού που καθορίζουν τη συμπεριφορά ζωντανών κλήσεων — η ανταλλαγή ρυθμίσεων telephony.incoming / web.incoming — περιορίζονται σε 10 δευτερόλεπτα για την πρώτη προσπάθεια μιας τηλεφωνικής κλήσης και σε 13 δευτερόλεπτα για ολόκληρη την ανταλλαγή, συμπεριλαμβανομένης της μίας επανάληψής της, και σε 10 δευτερόλεπτα για μια συνεδρία γραφικού στοιχείου. Μια αργή απόκριση καθυστερεί την απάντηση της κλήσης, επομένως επιδιώξτε να απαντάτε εντός λίγων δευτερολέπτων. Η αποστολή εργαλείων σε λειτουργία διαδικτυακής ειδοποίησης επιτρέπει 20 δευτερόλεπτα από προεπιλογή και οι δηλώσεις εργαλείων μπορούν να ορίσουν ένα timeout ανώτατου επιπέδου.

IP προέλευσης

Τα εξερχόμενα webhook προέρχονται από το εύρος IP cloud του ThunderPhone. Αν το τείχος προστασίας σας απαιτεί λίστα επιτρεπόμενων διευθύνσεων, επικοινωνήστε με την υποστήριξη και θα μοιραστούμε τα τρέχοντα εύρη.

Επιλογή μεταξύ webhook παλαιού τύπου και webhook βάσει τελικών σημείων

ΧαρακτηριστικόΠαλαιού τύπου (/v1/webhook)Τελικά σημεία (/v1/developer/webhook-endpoints)
Αριθμός URL1 ανά οργανισμόΠολλά ανά οργανισμό
Κάλυψη συμβάντωνΜόνο telephony.* / web.*Και οι 10 τύποι συμβάντων
Φίλτρο συμβάντων—Ανά τελικό σημείο
ΕπαναλήψειςΚαμία, εκτός από μία για την ανταλλαγή ρυθμίσεων της τηλεφωνικής κλήσης8 προσπάθειες σε διάστημα 24 ωρών
Φάκελοςtype + datatype + data + event_id
Εναλλαγή μυστικούΑντικαθιστά ένα μόνο μυστικόΜυστικό ανά τελικό σημείο
Απενεργοποίηση χωρίς διαγραφήPUT /v1/webhook with {"url": ""}status=disabled
Ορατότητα κατάστασης—active / disabled / failing
Ανταλλαγή ρυθμίσεων με αποκλεισμόΝαι (telephony.incoming / web.incoming)Ποτέ — μόνο ειδοποιήσεις
Κατάλληλο γιαΔυναμική ρύθμιση κλήσεωνΚατανάλωση συμβάντων στην παραγωγή

Οι νέες ενσωματώσεις θα πρέπει να καταναλώνουν συμβάντα μέσω webhook βάσει τελικών σημείων. Διατηρήστε (ή προσθέστε) μια διεύθυνση URL παλαιού τύπου μόνο αν ρυθμίζετε κλήσεις δυναμικά τη στιγμή της απάντησης ή χρησιμοποιείτε εκτέλεση εργαλείων σε λειτουργία webhook — αυτές οι ανταλλαγές αιτήματος/απόκρισης εκτελούνται μόνο στη διαδρομή παλαιού τύπου.


Σχετικά