---
title: "Webhookide ülevaade"
description: "Kuidas ThunderPhone edastab reaalajas sündmusi, kuidas allkirju kontrollida ning kuidas võrrelda pärand- ja lõpp-punktil põhinevaid edastusmudeleid."
---

ThunderPhone saadab sinu serverile HTTP `POST` päringuid, kui kõne ajal midagi
juhtub — sissetulev kõne algab, kõne lõpeb, hindamisprotsess lõpeb,
käivitub hoiatus jne. Saadaval on **kaks edastusmudelit**:

<CardGroup cols={2}>
  <Card title="Veebikonksu lõpp-punktid (soovitatav)" icon="bolt" href="/et/webhooks/endpoints">
    Mitu URL-i, lõpp-punktipõhised saladused, lõpp-punktipõhised sündmusefiltrid
    ja automaatsed korduskatsed.
    Halda kaudu `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints`.
  </Card>
  <Card title="Ühe URL-iga pärandveebikonks" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    Üks URL organisatsiooni kohta. Sisaldab kõne elutsükli sündmusi, sealhulgas
    **blokeerivaid** konfiguratsioonivahetusi. Hallatakse kaudu `GET/PUT /v1/webhook`.
  </Card>
</CardGroup>

Kõik kümme [sündmuste kataloogis](/et/webhooks/events) olevat sündmusetüüpi
edastatakse veebikonksu lõpp-punktide kaudu. Kuus kõne elutsükli sündmust
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) saadetakse **samuti**
ühe URL-iga pärandveebikonksu kaudu — kui sul on nii pärand-URL kui ka
sobiv lõpp-punkt, saad sündmuse **mõlemale** teele. Blokeeriv käitumine
([`telephony.incoming` / `web.incoming` konfiguratsioonivahetus](/et/webhooks/call-incoming) ja veebikonksurežiimi
[tööriista väljakutse](/et/tools/overview)) on ainult
pärandteel; iga lõpp-punkti edastus on teavitus, mis ei oota vastust.

## Andmevorming

Lõpp-punkti edastused on JSON-objektid väljadega `data`, `event_id` ja
`type`:

```json
{
  "data": {
    "call_id": 987654321,
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  },
  "event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
  "type": "telephony.incoming"
}
```

`event_id` on iga väljastatud sündmuse jaoks kordumatu. See on sama nii
korduskatsete **kui ka** iga sündmuse saanud lõpp-punkti puhul — kasuta seda duplikaatide eemaldamiseks.

Ühe URL-iga pärandveebikonks saadab sama `type` ja `data`, kuid
**ilma** `event_id`-ta:

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

Võrgus serialiseeritakse iga sisu kanooniliselt — võtmed sorditakse
tähestikulises järjekorras, tühikuid pole, kodeering on UTF-8. Nendes
dokumentides olevad vormindatud näited on ainult loetavuse huvides.

Täieliku sündmusetüüpide ja andmeväljade loendi leiad
[sündmuste kataloogist](/et/webhooks/events).

## Allkirja kontrollimine

Iga päring sisaldab päises `X-ThunderPhone-Signature` HMAC-SHA256 allkirja, mis on arvutatud **toorpäringu
sisust**. Allkirjastamisvõti on lõpp-punkti `secret` (või pärand-edastuste korral sinu organisatsioonitaseme veebikonksu `secret`).

### Sammud

1. Loe toorpäringu sisu **enne** mis tahes parsimist.
2. Arvuta `hmac_sha256(secret, body).hexdigest()`.
3. Võrdle tulemust konstantse ajaga päisega `X-ThunderPhone-Signature`.

Allkirjastame täpselt need baidid, mida edastame, ning need baidid on
kanoniseeritud JSON-i serialiseering (sorditud võtmed, kompaktsed eraldajad). Seega töötab kontrollimine toorsisu alusel alati — ja kui sinu raamistik annab sulle ainult parsitud JSON-i, tekitab selle uuesti serialiseerimine sorditud võtmete ja kompaktsete eraldajatega identsed baidid. Mõlemat meetodit käsitletakse [kontrollimise juhendis](/et/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>

## Edastamise semantika

Need semantikad kehtivad **lõpp-punkti** edastustele. Pärandne ühe URL-iga
veebikonks teeb ühe sünkroonse katse ilma korduskatseteta.

<AccordionGroup>
  <Accordion title="Korduskatsed">
    Iga sündmust proovitakse kohe üks kord edastada. Mis tahes `2xx` vastus
    kinnitab edastuse. Mis tahes muu tulemuse korral (mitte-2xx,
    ühenduse viga, ajalõpp) proovime uuesti **1 min, 5 min, 30 min, 2 h, 6 h,
    12 h ja 24 h pärast esimest katset** — 8 katset 24 tunni jooksul.
    Kui kõik katsed ebaõnnestuvad, edastamine peatub ja lõpp-punkt
    märgitakse olekuga `status="failing"`
    [veebikonksu lõpp-punktides](/et/webhooks/endpoints). Tagasta `2xx` kohe,
    kui andmekoormus on püsivalt vastu võetud; töötle seda asünkroonselt.
  </Accordion>

  <Accordion title="Järjestus">
    Edastamise järjestus on parima võimaliku pingutuse põhine. Praktikas
    edastame sündmused nende väljastamise järjekorras, kuid ebaõnnestumise
    korral võivad korduskatsed järjekorda muuta. Eemalda alati duplikaadid ja
    ühtlusta andmed `call_id` / objekti ID alusel.
  </Accordion>

  <Accordion title="Duplikaadid">
    Edastamine toimub **vähemalt üks kord**: korduskatse pärast vastust,
    mida me ei näinud, võib sündmuse dubleerida. Iga korduskatse sisaldab sama
    `event_id`, seega salvesta töödeldud ID-d ja jäta kordused vahele. `event_id`
    on ühine ka lõpp-punktide vahel — kaks sama sündmust tellinud lõpp-punkti
    saavad sama `event_id`.
  </Accordion>

  <Accordion title="Ajalõpud">
    Lõpp-punkti edastustel on iga katse kohta **30 s** ajalimiit. Pärandteel
    aeguvad reaalajas kõnekäitumist mõjutavad blokeerivad päringud —
    [`telephony.incoming` / `web.incoming`](/et/webhooks/call-incoming)
    konfiguratsioonivahetus — **10 s** pärast, kuid aeglane vastus lükkab
    kõnele vastamist edasi, seega püüa vastata paari sekundi jooksul.
    Veebikonksurežiimis [tööriista väljakutsumine](/et/tools/overview) lubab
    vaikimisi 20 s ning tööriista deklaratsioonid võivad määrata tipptaseme
    `timeout`.
  </Accordion>

  <Accordion title="Lähte-IP-d">
    Väljuvad veebikonksud pärinevad ThunderPhone'i pilve IP-vahemikust.
    Kui sinu tulemüür nõuab lubatud loendit, võta ühendust toega ja jagame
    praeguseid vahemikke.
  </Accordion>
</AccordionGroup>

## Valimine pärandsete ja lõpp-punktipõhiste veebikonksude vahel

| Funktsioon | Pärand (`/v1/webhook`) | Lõpp-punktid (`/v1/developer/webhook-endpoints`) |
|---------|------------------------|----------------------------------------------|
| URL-ide arv | 1 organisatsiooni kohta | Mitu organisatsiooni kohta |
| Sündmuste katvus | ainult `telephony.*` / `web.*` | Kõik 10 sündmusetüüpi |
| Sündmuste filter | — | Lõpp-punkti kaupa |
| Korduskatsed | Puuduvad | 8 katset 24 h jooksul |
| Ümbris | `type` + `data` | `type` + `data` + `event_id` |
| Saladuse roteerimine | Asendab ühe saladuse | Lõpp-punkti saladus |
| Keelamine kustutamata | `PUT /v1/webhook` koos `{"url": ""}` | `status=disabled` |
| Oleku nähtavus | — | `active` / `disabled` / `failing` |
| Blokeeriv konfiguratsioonivahetus | Jah ([`telephony.incoming` / `web.incoming`](/et/webhooks/call-incoming)) | Mitte kunagi — ainult teavitused |
| Sobib kõige paremini | Dünaamiline kõnede konfigureerimine | Sündmuste töötlemine tootmises |

Uued integratsioonid peaksid sündmusi vastu võtma lõpp-punktipõhiste
veebikonksude kaudu. Hoia (või lisa) pärand-URL ainult siis, kui
konfigureerid kõnesid dünaamiliselt kõnele vastamise ajal või kasutad
veebikonksurežiimis tööriista väljakutsumist — need päringu/vastuse
vahetused toimivad ainult pärandteel.

---

## Seotud

<CardGroup cols={2}>
  <Card title="Sündmuste kataloog" icon="list" href="/et/webhooks/events">
    Kõik sündmusetüübid ja nende andmekoormused.
  </Card>
  <Card title="Veebikonksu lõpp-punktid" icon="bolt" href="/et/webhooks/endpoints">
    Halda mitut lõpp-punkti, sündmuste filtreid ja saladusi.
  </Card>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/et/webhooks/call-incoming">
    Blokeeriv päring, millele sinu server peab kõnede konfigureerimiseks vastama.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone" href="/et/webhooks/call-complete">
    Kõnejärgne andmekoormus koos transkriptsiooni, salvestise ja mõõdikutega.
  </Card>
</CardGroup>
