---
title: "Webhookien yleiskatsaus"
description: "Miten ThunderPhone toimittaa reaaliaikaisia tapahtumia, miten allekirjoitukset vahvistetaan ja miten vanha toimitusmalli vertautuu päätepistepohjaiseen toimitusmalliin."
---

ThunderPhone lähettää HTTP `POST` -pyyntöjä palvelimellesi, kun puhelun aikana
tapahtuu asioita — saapuva puhelu alkaa, puhelu päättyy, arviointiajo
valmistuu, hälytys laukeaa ja niin edelleen. Käytössä on **kaksi toimitusmallia**:

<CardGroup cols={2}>
  <Card title="Webhook-päätepisteet (suositeltu)" icon="bolt" href="/fi/webhooks/endpoints">
    Useita URL-osoitteita, päätepistekohtaiset salaisuudet, päätepistekohtaiset tapahtumasuodattimet
    ja automaattiset uudelleenyritykset.
    Hallitse käyttämällä komentoa `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints`.
  </Card>
  <Card title="Vanha yhden URL-osoitteen webhook" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    Yksi URL-osoite organisaatiota kohden. Välittää puhelun elinkaaren tapahtumat, mukaan lukien
    **estävät** määritysvaihdot. Hallitaan komennolla `GET/PUT /v1/webhook`.
  </Card>
</CardGroup>

Kaikki [tapahtumaluettelossa](/fi/webhooks/events) luetellut tapahtumatyypit
toimitetaan webhook-päätepisteiden kautta. Kuusi puhelun elinkaaren tapahtumaa
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) lähetetään **myös**
vanhaan yhden URL-osoitteen webhookiin — jos käytössäsi on sekä vanha URL-osoite että
vastaava päätepiste, saat tapahtuman **molempia** reittejä pitkin. Estävä
toiminta ([`telephony.incoming` / `web.incoming` -määritysvaihto](/fi/webhooks/call-incoming)
ja webhook-tilan [työkalun välitys](/fi/tools/overview))
on käytettävissä vain vanhalla reitillä; jokainen päätepistetoimitus on
ilmoitus, johon ei odoteta vastausta.

## Hyötykuorman muoto

Päätepistetoimitukset ovat JSON-objekteja, joissa on `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 yksilöllinen jokaiselle lähetetylle tapahtumalle. Se on sama uudelleenyrityksissä
**ja** kaikissa tapahtuman vastaanottavissa päätepisteissä — poista
kaksoiskappaleet sen perusteella.

Vanha yhden URL-osoitteen webhook lähettää saman `type`- ja `data`-sisällön, mutta
**ilman** `event_id`-kenttää:

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

Siirrettäessä jokainen runko sarjoitetaan kanonisesti — avaimet lajitellaan
aakkosjärjestykseen, välilyöntejä ei käytetä ja merkistönä on UTF-8. Näiden
dokumenttien kauniisti muotoillut esimerkit ovat vain luettavuuden vuoksi.

Katso [tapahtumaluettelosta](/fi/webhooks/events) täydellinen luettelo tapahtuma-
tyypeistä ja hyötykuormakentistä.

## Allekirjoituksen vahvistaminen

Jokaisessa pyynnössä on kaksi allekirjoitusta, jotka molemmat ovat HMAC-SHA256-allekirjoituksia päätepisteen `secret`-avaimella (tai organisaatiotason webhookin `secret`-avaimella vanhoja toimituksia varten):

- `X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex>` allekirjoittaa
  aikaleiman, metodin, polun ja kyselyparametrit sekä raakarungon. Vahvista
  tämä allekirjoitus ja hylkää pyynnöt, joiden `t` poikkeaa kellostasi yli **5 minuuttia**,
  jotta kaapattua pyyntöä ei voi toistaa myöhemmin. Uudelleenyritykset
  allekirjoitetaan uudelleen, kun ne lähetetään.
- `X-ThunderPhone-Signature` allekirjoittaa vain raakarungon. Se lähetetään edelleen
  muuttumattomana, jotta nykyiset vahvistajat toimivat edelleen.

### Vaiheet

1. Lue otsake, metodi, raakapolku ja kysely sekä raaka
   runko **ennen** jäsentämistä.
2. Laske salaisuuttasi käyttäen heksamuotoinen HMAC-SHA256 arvosta
   `<t>\n<METHOD>\n<path and query>\n<body>`.
3. Hylkää pyyntö, jos `t` poikkeaa yli 300 sekuntia tai jos
   tulos ei vastaa arvoa `v1` vakioaikaisessa vertailussa.

Rungot ovat kanonista JSON-sarjallistusta (lajitellut avaimet, tiiviit
erottimet), ja allekirjoitamme täsmälleen lähettämämme tavut.
[vahvistusoppaassa](/fi/guides/verify-webhook-signatures) ovat tarkka
allekirjoitettava merkkijono, käytännön esimerkki, SDK:ta käyttämätön koodi
ja vanha otsake.

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

```javascript 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);
  },
);
```
</CodeGroup>

## Toimitussemantiikka

Nämä semantiikat koskevat **päätepisteen** toimituksia. Vanha yhden URL-osoitteen
webhook tekee yhden synkronisen yrityksen ilman uudelleenyrityksiä, lukuun ottamatta
puhelun [`telephony.incoming`](/fi/webhooks/call-incoming)
määritysvaihtoa, joka yritetään uudelleen kerran.

<AccordionGroup>
  <Accordion title="Uudelleenyritykset">
    Jokaista tapahtumaa yritetään kerran välittömästi. Mikä tahansa `2xx`-vastaus
    kuittaa toimituksen. Kaikissa muissa tapauksissa (muu kuin 2xx,
    yhteysvirhe, aikakatkaisu) yritämme uudelleen **1 min, 5 min, 30 min, 2 h, 6 h,
    12 h ja 24 h ensimmäisen yrityksen jälkeen** — yhteensä 8 yritystä
    24 tunnin aikana. Jos kaikki yritykset epäonnistuvat, toimitus pysähtyy ja päätepiste
    merkitään tilaan `status="failing"`
    [webhook-päätepisteissä](/fi/webhooks/endpoints); lähetämme sähköpostia organisaatiosi
    omistajille ja ylläpitäjille sekä näytämme tiedon hallintapaneelissa. Palauta `2xx` heti,
    kun hyötykuorma on hyväksytty pysyvästi; käsittele se asynkronisesti.
    Päätepisteen testaus-API:n testilähetyksiä yritetään uudelleen kerran noin minuutin kuluttua
    ensimmäisestä yrityksestä, eivätkä ne koskaan muuta päätepisteen tilaa.
  </Accordion>

  <Accordion title="Järjestys">
    Toimitusjärjestys pyritään säilyttämään parhaan mahdollisen mukaan. Käytännössä toimitamme tapahtumat
    niiden lähetysjärjestyksessä, mutta uudelleenyritykset voivat muuttaa järjestystä epäonnistumisen yhteydessä.
    Poista aina kaksoiskappaleet ja täsmäytä tiedot `call_id`-tunnuksen / objektitunnuksen perusteella.
  </Accordion>

  <Accordion title="Kaksoiskappaleet">
    Toimitus tapahtuu **vähintään kerran**: uudelleenyritys vastauksen jälkeen, jota emme koskaan
    nähneet, voi luoda tapahtumasta kaksoiskappaleen. Jokaisella uudelleenyrityksellä on sama
    `event_id`, joten tallenna käsitellyt tunnukset ja ohita toistot. `event_id` on
    myös jaettu päätepisteiden välillä — kaksi samaa tapahtumaa tilaavaa päätepistettä
    vastaanottaa saman `event_id`-tunnuksen.
  </Accordion>

  <Accordion title="Aikakatkaisut">
    Päätepisteen toimituksilla on **30 s** aikakatkaisu yritystä kohden. Vanhassa
    polussa reaaliaikaista puhelukäyttäytymistä ohjaavat estävät pyynnöt —
    [`telephony.incoming` / `web.incoming`](/fi/webhooks/call-incoming)
    määritysvaihto — on rajoitettu **10 s** puhelun
    ensimmäisessä yrityksessä ja **13 s** koko vaihdolle, mukaan lukien sen yksi
    uudelleenyritys, sekä **10 s** widget-istunnolle. Hidas vastaus viivästyttää
    puheluun vastaamista, joten pyri vastaamaan muutamassa sekunnissa. Webhook-tilan [työkalun lähetys](/fi/tools/overview) sallii oletusarvoisesti 20 s
    ja työkalumäärityksissä voidaan asettaa ylimmän tason `timeout`.
  </Accordion>

  <Accordion title="Lähtö-IP-osoitteet">
    Lähtevät webhookit tulevat ThunderPhonen pilvipalvelun IP-osoitealueelta.
    Jos palomuurisi edellyttää sallittujen osoitteiden luetteloa, ota yhteyttä tukeen, niin
    jaamme nykyiset alueet.
  </Accordion>
</AccordionGroup>

## Valinta vanhojen ja päätepistepohjaisten webhookien välillä

| Ominaisuus | Legacy (`/v1/webhook`) | Päätepisteet (`/v1/developer/webhook-endpoints`) |
|---------|------------------------|----------------------------------------------|
| URL-osoitteiden määrä | 1 organisaatiota kohden | Useita organisaatiota kohden |
| Tapahtumakattavuus | Vain `telephony.*` / `web.*` | Kaikki 10 tapahtumatyyppiä |
| Tapahtumasuodatin | — | Päätepistekohtainen |
| Uudelleenyritykset | Ei lainkaan, lukuun ottamatta yhtä puhelun asetustenvaihtoa | 8 yritystä 24 tunnin aikana |
| Kirjekuori | `type` + `data` | `type` + `data` + `event_id` |
| Salaisuuden kierto | Korvaa yksittäisen salaisuuden | Päätepistekohtainen salaisuus |
| Poista käytöstä poistamatta | `PUT /v1/webhook` ja `{"url": ""}` | `status=disabled` |
| Tilan näkyvyys | — | `active` / `disabled` / `failing` |
| Estävä asetustenvaihto | Kyllä ([`telephony.incoming` / `web.incoming`](/fi/webhooks/call-incoming)) | Ei koskaan — vain ilmoituksia |
| Sopii parhaiten | Dynaaminen puhelun määritys | Tapahtumien käsittely tuotannossa |

Uusien integraatioiden tulee vastaanottaa tapahtumat päätepistepohjaisten
webhookien kautta. Säilytä (tai lisää) vanha URL-osoite vain, jos määrität puhelut
dynaamisesti puheluun vastaamisen yhteydessä tai käytät webhook-tilan työkalujen välitystä — nämä
pyyntö-/vastausvaihdot toimivat vain vanhalla reitillä.

---

## Aiheeseen liittyvät

<CardGroup cols={2}>
  <Card title="Tapahtumaluettelo" icon="list" href="/fi/webhooks/events">
    Kaikki tapahtumatyypit ja niiden hyötykuormat.
  </Card>
  <Card title="Webhook-päätepisteet" icon="bolt" href="/fi/webhooks/endpoints">
    Hallitse useita päätepisteitä, tapahtumasuodattimia ja salaisuuksia.
  </Card>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/fi/webhooks/call-incoming">
    Estävä pyyntö, johon palvelimesi on vastattava puhelujen määrittämiseksi.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone" href="/fi/webhooks/call-complete">
    Puhelun jälkeinen hyötykuorma, joka sisältää litteroinnin, tallenteen ja mittarit.
  </Card>
</CardGroup>
