---
title: "Pregled spletnih kljuk"
description: "Kako ThunderPhone dostavlja dogodke v realnem času, kako preveriti podpise ter kako se primerjata zastareli model dostave in model dostave, ki temelji na končnih točkah."
---

ThunderPhone pošlje zahteve HTTP `POST` vašemu strežniku, ko se med
klicem nekaj zgodi — začne se dohodni klic, klic se konča, ocenjevanje
se zaključi, sproži se opozorilo in podobno. Obstajata **dva modela
dostave**:

<CardGroup cols={2}>
  <Card title="Končne točke webhookov (priporočeno)" icon="bolt" href="/sl/webhooks/endpoints">
    Več URL-jev, skrivnosti za posamezne končne točke, filtri dogodkov za posamezne končne točke
    in samodejni ponovni poskusi.
    Upravljajte prek `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints`.
  </Card>
  <Card title="Zastareli webhook z enim URL-jem" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    En URL na organizacijo. Vsebuje dogodke življenjskega cikla klica, vključno z
    **blokirajočimi** izmenjavami konfiguracije. Upravljajte prek `GET/PUT /v1/webhook`.
  </Card>
</CardGroup>

Vseh deset vrst dogodkov v [katalogu dogodkov](/sl/webhooks/events) je
dostavljenih prek končnih točk webhookov. Šest dogodkov življenjskega cikla klica
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) je **prav tako** poslanih v
zastareli webhook z enim URL-jem — če imate zastareli URL in ujemajočo se
končno točko, dogodek prejmete po **obeh** poteh. Blokirajoče
vedenje ( [izmenjava konfiguracije `telephony.incoming` / `web.incoming`](/sl/webhooks/call-incoming) in
odpošiljanje [orodij](/sl/tools/overview) v načinu webhook)
je na voljo izključno na zastareli poti; vsaka dostava v končno točko je
obvestilo brez čakanja na odgovor.

## Oblika koristnega tovora

Dostave v končne točke so objekt JSON s polji `data`, `event_id` in
`type`:

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

`event_id` je edinstven za vsak poslan dogodek. Med ponovnimi poskusi je enak
**in** enak je za vsako končno točko, ki prejme dogodek — uporabite ga za
odstranjevanje dvojnikov.

Zastareli webhook z enim URL-jem pošlje enaka `type` in `data`, vendar
**brez** `event_id`:

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

Pri prenosu je vsako telo serijsko zapisano kanonično — ključi so razvrščeni
po abecedi, brez presledkov, v UTF-8. Lepo oblikovani primeri v tej
dokumentaciji so namenjeni zgolj berljivosti.

Za celoten seznam vrst dogodkov in polj koristnega tovora glejte
[katalog dogodkov](/sl/webhooks/events).

## Preverjanje podpisa

Vsaka zahteva vsebuje podpis HMAC-SHA256 nad **surovim telesom
zahteve** v glavi `X-ThunderPhone-Signature`. Podpisni ključ je `secret`
končne točke (ali `secret` spletnega kavlja na ravni vaše organizacije za
podedovane dostave).

### Koraki

1. Preberite surovo telo zahteve **pred** kakršnim koli razčlenjevanjem.
2. Izračunajte `hmac_sha256(secret, body).hexdigest()`.
3. V konstantnem času primerjajte z glavo `X-ThunderPhone-Signature`.

Podpišemo natanko bajte, ki jih pošljemo, ti bajti pa so kanonična
serializacija JSON (razvrščeni ključi, strnjena ločila). Zato preverjanje
surovega telesa vedno deluje — in če vam vaše ogrodje posreduje samo
razčlenjeni JSON, ponovna serializacija z razvrščenimi ključi in strnjenimi
ločili ustvari enake bajte. Oba postopka sta opisana v
[vodniku za preverjanje](/sl/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>

## Semantika dostave

Ta semantika velja za dostave v **končno točko**. Zastareli webhook z enim URL-jem je en sam sinhroni poskus brez ponovnih poskusov.

<AccordionGroup>
  <Accordion title="Ponovni poskusi">
    Vsak dogodek se takoj poskusi dostaviti enkrat. Vsak odgovor `2xx`
    potrdi dostavo. Pri katerem koli drugem izidu (ki ni 2xx,
    napaka povezave, časovna omejitev) ponovno poskusimo **1 min, 5 min, 30 min, 2 h, 6 h,
    12 h in 24 h po prvem poskusu** — 8 poskusov v
    24 urah. Če vsi poskusi ne uspejo, se dostava ustavi, končna točka
    pa je v [končnih točkah webhookov](/sl/webhooks/endpoints) označena s
    `status="failing"`. Vrnite `2xx`, takoj ko je koristni tovor
    trajno sprejet; obdelajte ga asinhrono.
  </Accordion>

  <Accordion title="Vrstni red">
    Vrstni red dostave temelji na najboljšem možnem prizadevanju. V praksi dostavljamo v
    vrstnem redu, v katerem so dogodki poslani, vendar lahko ponovni poskusi ob napaki
    spremenijo vrstni red. Vedno odstranite podvojitve in uskladite podatke po `call_id` / ID-ju objekta.
  </Accordion>

  <Accordion title="Podvojitve">
    Dostava je **vsaj enkratna**: ponovni poskus po odgovoru, ki ga nismo
    prejeli, lahko podvoji dogodek. Vsak ponovni poskus vsebuje isti
    `event_id`, zato shranite obdelane ID-je in preskočite ponovitve. `event_id` se
    deli tudi med končnimi točkami — dve končni točki, naročeni na isti
    dogodek, prejmeta isti `event_id`.
  </Accordion>

  <Accordion title="Časovne omejitve">
    Dostave v končne točke imajo časovno omejitev **30 s** za posamezen poskus. Na
    zastareli poti se blokirajoče zahteve, ki usmerjajo vedenje klica v živo —
    izmenjava konfiguracije [`telephony.incoming` / `web.incoming`](/sl/webhooks/call-incoming) —
    časovno omejijo po **10 s**, vendar počasen odgovor zamakne prevzem klica,
    zato si prizadevajte odgovoriti v nekaj sekundah. Odprema [orodij](/sl/tools/overview) v načinu webhook
    privzeto omogoča 20 s, deklaracije orodij pa lahko nastavijo `timeout` na najvišji ravni.
  </Accordion>

  <Accordion title="Izvorni IP-naslovi">
    Odhodni webhooki izvirajo iz obsega IP-naslovov v oblaku ThunderPhone.
    Če vaš požarni zid zahteva seznam dovoljenih naslovov, se obrnite na podporo in
    posredovali vam bomo trenutne obsege.
  </Accordion>
</AccordionGroup>

## Izbira med zastarelimi webhooki in webhooki na podlagi končnih točk

| Značilnost | Zastareli (`/v1/webhook`) | Končne točke (`/v1/developer/webhook-endpoints`) |
|---------|------------------------|----------------------------------------------|
| Število URL-jev | 1 na organizacijo | Več na organizacijo |
| Pokritost dogodkov | Samo `telephony.*` / `web.*` | Vseh 10 vrst dogodkov |
| Filter dogodkov | — | Po končni točki |
| Ponovni poskusi | Brez | 8 poskusov v 24 h |
| Ovojnica | `type` + `data` | `type` + `data` + `event_id` |
| Menjava skrivnosti | Zamenja eno skrivnost | Skrivnost za posamezno končno točko |
| Onemogočanje brez brisanja | `PUT /v1/webhook` z `{"url": ""}` | `status=disabled` |
| Vidnost stanja | — | `active` / `disabled` / `failing` |
| Blokirajoča izmenjava konfiguracije | Da ([`telephony.incoming` / `web.incoming`](/sl/webhooks/call-incoming)) | Nikoli — samo obvestila |
| Najprimernejše za | Dinamično konfiguracijo klicev | Prejemanje dogodkov v produkciji |

Nove integracije naj prejemajo dogodke prek webhookov na podlagi
končnih točk. Zastareli URL obdržite (ali ga dodajte) samo, če klice
dinamično konfigurirate ob prevzemu ali uporabljate odpošiljanje orodij v načinu webhook — te
izmenjave zahtev in odgovorov se izvajajo samo na zastareli poti.

---

## Povezano

<CardGroup cols={2}>
  <Card title="Katalog dogodkov" icon="list" href="/sl/webhooks/events">
    Vse vrste dogodkov in njihovi koristni tovori.
  </Card>
  <Card title="Končne točke webhookov" icon="bolt" href="/sl/webhooks/endpoints">
    Upravljajte več končnih točk, filtre dogodkov in skrivnosti.
  </Card>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/sl/webhooks/call-incoming">
    Blokirajoča zahteva, na katero mora vaš strežnik odgovoriti za konfiguracijo klicev.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone" href="/sl/webhooks/call-complete">
    Koristni tovor po klicu s prepisom, posnetkom in meritvami.
  </Card>
</CardGroup>
