---
title: "Επισκόπηση Webhooks"
description: "Πώς το ThunderPhone παραδίδει συμβάντα σε πραγματικό χρόνο, πώς να επαληθεύετε υπογραφές και πώς συγκρίνονται τα παλαιότερα και τα βασισμένα σε τελικά σημεία μοντέλα παράδοσης."
---

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

<CardGroup cols={2}>
  <Card title="Τελικά σημεία webhook (συνιστάται)" icon="bolt" href="/el/webhooks/endpoints">
    Πολλαπλά URL, μυστικά ανά τελικό σημείο, φίλτρα συμβάντων ανά τελικό σημείο
    και αυτόματες επαναλήψεις.
    Διαχειριστείτε τα μέσω `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints`.
  </Card>
  <Card title="Παρωχημένο webhook ενός URL" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    Ένα URL ανά οργανισμό. Μεταφέρει τα συμβάντα κύκλου ζωής κλήσης, συμπεριλαμβανομένων των
    **αποκλειστικών** ανταλλαγών ρυθμίσεων. Διαχειρίζεται μέσω `GET/PUT /v1/webhook`.
  </Card>
</CardGroup>

Και οι δέκα τύποι συμβάντων στον [κατάλογο συμβάντων](/el/webhooks/events)
παραδίδονται μέσω τελικών σημείων webhook. Τα έξι συμβάντα κύκλου ζωής κλήσης
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) αποστέλλονται **επίσης** στο
παρωχημένο webhook ενός URL — αν έχετε και παρωχημένο URL και αντίστοιχο
τελικό σημείο, λαμβάνετε το συμβάν και από τις **δύο** διαδρομές. Η αποκλειστική
συμπεριφορά (η [ανταλλαγή ρυθμίσεων `telephony.incoming` / `web.incoming`](/el/webhooks/call-incoming)
και η [αποστολή εργαλείων](/el/tools/overview) σε λειτουργία webhook)
υπάρχει αποκλειστικά στην παρωχημένη διαδρομή· κάθε παράδοση σε τελικό σημείο είναι
ειδοποίηση χωρίς αναμονή απάντησης.

## Μορφή φορτίου

Οι παραδόσεις σε τελικά σημεία είναι αντικείμενο JSON με `data`, `event_id` και
`type`:

```json
{
  "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`:

```json
{
  "type": "telephony.incoming",
  "data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}
```

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

Δείτε τον [Κατάλογο συμβάντων](/el/webhooks/events) για την πλήρη λίστα τύπων
συμβάντων και πεδίων φορτίου.

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

Κάθε αίτημα φέρει υπογραφή HMAC-SHA256 πάνω στο **ακατέργαστο σώμα
αιτήματος** στην κεφαλίδα `X-ThunderPhone-Signature`. Το κλειδί υπογραφής είναι το
`secret` του endpoint (ή το `secret` του webhook σε επίπεδο οργανισμού για
παλαιότερες παραδόσεις).

### Βήματα

1. Διαβάστε το ακατέργαστο σώμα αιτήματος **πριν** από οποιαδήποτε ανάλυση.
2. Υπολογίστε το `hmac_sha256(secret, body).hexdigest()`.
3. Συγκρίνετε σε σταθερό χρόνο με την κεφαλίδα `X-ThunderPhone-Signature`.

Υπογράφουμε ακριβώς τα byte που μεταδίδουμε, και αυτά τα byte είναι η
κανονική σειριοποίηση JSON (ταξινομημένα κλειδιά, συμπαγή διαχωριστικά). Επομένως,
η επαλήθευση με βάση το ακατέργαστο σώμα λειτουργεί πάντα — και αν το framework σας
σάς παρέχει μόνο αναλυμένο JSON, η εκ νέου σειριοποίησή του με ταξινομημένα κλειδιά και
συμπαγή διαχωριστικά παράγει πανομοιότυπα byte. Και οι δύο μέθοδοι
καλύπτονται στον [οδηγό επαλήθευσης](/el/guides/verify-webhook-signatures).

<CodeGroup>
```python Python
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
```

```javascript Node.js (Express)
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);
  },
);
```
</CodeGroup>

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

Αυτή η σημασιολογία εφαρμόζεται σε παραδόσεις σε **τελικά σημεία**. Το παλαιό webhook μίας μόνο διεύθυνσης URL
είναι μία σύγχρονη προσπάθεια χωρίς επαναλήψεις.

<AccordionGroup>
  <Accordion title="Επαναλήψεις">
    Κάθε συμβάν επιχειρείται μία φορά άμεσα. Κάθε απόκριση `2xx`
    επιβεβαιώνει την παράδοση. Σε κάθε άλλο αποτέλεσμα (μη-2xx,
    σφάλμα σύνδεσης, χρονικό όριο) επαναλαμβάνουμε στις **1 λ., 5 λ., 30 λ., 2 ω.,
    6 ω., 12 ω. και 24 ω. μετά την πρώτη προσπάθεια** — 8 προσπάθειες σε διάστημα
    24 ωρών. Αν αποτύχει κάθε προσπάθεια, η παράδοση διακόπτεται και το τελικό σημείο
    επισημαίνεται με `status="failing"` στα
    [τελικά σημεία webhook](/el/webhooks/endpoints). Επιστρέψτε `2xx` μόλις
    το ωφέλιμο φορτίο γίνει αποδεκτό με ανθεκτικό τρόπο· επεξεργαστείτε το ασύγχρονα.
  </Accordion>

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

  <Accordion title="Διπλότυπα">
    Η παράδοση είναι **τουλάχιστον μία φορά**: μια επανάληψη μετά από απόκριση που δεν
    λάβαμε μπορεί να δημιουργήσει διπλότυπο συμβάν. Κάθε επανάληψη περιλαμβάνει το ίδιο
    `event_id`, επομένως αποθηκεύστε τα επεξεργασμένα αναγνωριστικά και παραλείψτε τις επαναλήψεις. Το `event_id`
    κοινοποιείται επίσης μεταξύ τελικών σημείων — δύο τελικά σημεία που είναι εγγεγραμμένα στο
    ίδιο συμβάν λαμβάνουν το ίδιο `event_id`.
  </Accordion>

  <Accordion title="Χρονικά όρια">
    Οι παραδόσεις σε τελικά σημεία έχουν χρονικό όριο **30 δ.** ανά προσπάθεια. Στην
    παλαιά διαδρομή, τα αιτήματα αποκλεισμού που καθορίζουν τη συμπεριφορά ζωντανών κλήσεων — η
    ανταλλαγή ρυθμίσεων [`telephony.incoming` / `web.incoming`](/el/webhooks/call-incoming) —
    λήγουν μετά από **10 δ.**, αλλά μια αργή απόκριση καθυστερεί την απάντηση της κλήσης,
    επομένως στοχεύστε να απαντάτε εντός λίγων δευτερολέπτων. Η [εκτέλεση εργαλείων](/el/tools/overview)
    σε λειτουργία webhook επιτρέπει 20 δ. από προεπιλογή και οι δηλώσεις εργαλείων
    μπορούν να ορίσουν `timeout` ανώτατου επιπέδου.
  </Accordion>

  <Accordion title="IP προέλευσης">
    Τα εξερχόμενα webhook προέρχονται από το εύρος IP cloud του ThunderPhone.
    Αν το τείχος προστασίας σας απαιτεί λίστα επιτρεπόμενων, επικοινωνήστε με την υποστήριξη και θα
    κοινοποιήσουμε τα τρέχοντα εύρη.
  </Accordion>
</AccordionGroup>

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

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

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

---

## Σχετικά

<CardGroup cols={2}>
  <Card title="Κατάλογος συμβάντων" icon="list" href="/el/webhooks/events">
    Όλοι οι τύποι συμβάντων και τα ωφέλιμα φορτία τους.
  </Card>
  <Card title="Τελικά σημεία webhook" icon="bolt" href="/el/webhooks/endpoints">
    Διαχειριστείτε πολλά τελικά σημεία, φίλτρα συμβάντων και μυστικά.
  </Card>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/el/webhooks/call-incoming">
    Το αίτημα αποκλεισμού στο οποίο πρέπει να απαντήσει ο διακομιστής σας για τη ρύθμιση κλήσεων.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone" href="/el/webhooks/call-complete">
    Ωφέλιμο φορτίο μετά την κλήση με απομαγνητοφώνηση, εγγραφή και μετρήσεις.
  </Card>
</CardGroup>
