---
title: "Översikt över webhooks"
description: "Hur ThunderPhone levererar händelser i realtid, hur du verifierar signaturer och hur de äldre och endpointbaserade leveransmodellerna jämförs."
---

ThunderPhone skickar HTTP-`POST`-begäranden till din server när saker
händer under ett samtal — ett inkommande samtal startar, ett samtal avslutas, en utvärderingskörning slutförs, en avisering utlöses och så vidare. Det finns **två leveransmodeller**:

<CardGroup cols={2}>
  <Card title="Webhook-slutpunkter (rekommenderas)" icon="bolt" href="/sv/webhooks/endpoints">
    Flera URL:er, hemligheter per slutpunkt, händelsefilter per slutpunkt
    och automatiska återförsök.
    Hantera via `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints`.
  </Card>
  <Card title="Äldre webhook med en URL" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    En URL per organisation. Innehåller händelser för samtalets livscykel, inklusive
    de **blockerande** konfigurationsutbytena. Hanteras via `GET/PUT /v1/webhook`.
  </Card>
</CardGroup>

Alla listade händelsetyper i [händelsekatalogen](/sv/webhooks/events)
levereras via webhook-slutpunkter. De sex händelserna för samtalets livscykel
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) skickas **också** till den
äldre webhooken med en URL — om du har både en äldre URL och en
matchande slutpunkt får du händelsen på **båda** sökvägarna. Blockerande
beteende (konfigurationsutbytet för
[`telephony.incoming` / `web.incoming`](/sv/webhooks/call-incoming) och
[verktygsdirigering](/sv/tools/overview) i webhook-läge)
finns endast på den äldre sökvägen; varje leverans till en slutpunkt är en
skicka-och-glöm-avisering.

## Payloadformat

Leveranser till slutpunkter är ett JSON-objekt med `data`, `event_id` och
`type`:

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

`event_id` är unikt för varje skickad händelse. Det är identiskt vid återförsök
**och** för varje slutpunkt som tar emot händelsen — deduplicera utifrån det.

Den äldre webhooken med en URL skickar samma `type` och `data`, men
**utan** `event_id`:

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

Vid överföring serialiseras varje brödtext kanoniskt — nycklar sorteras
alfabetiskt, utan blanksteg, UTF-8. De formaterade exemplen i den här
dokumentationen är endast för läsbarhet.

Se [händelsekatalogen](/sv/webhooks/events) för den fullständiga listan över händelsetyper
och payloadfält.

## Signaturverifiering

Varje begäran har två signaturer, båda HMAC-SHA256 med endpointens
`secret` som nyckel (eller din organisations webhook-`secret` för äldre
leveranser):

- `X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex>` signerar
  tidsstämpeln, metoden, sökvägen och frågesträngen samt den råa brödtexten. Verifiera
  denna och avvisa begäranden vars `t` skiljer sig med mer än **5 minuter** från
  din klocka, så att en uppfångad begäran inte kan spelas upp igen senare. Omförsök
  signeras på nytt när de skickas.
- `X-ThunderPhone-Signature` signerar endast den råa brödtexten. Den skickas fortfarande
  oförändrad så att befintliga verifierare fortsätter att fungera.

### Steg

1. Läs headern, metoden, den råa sökvägen och frågesträngen samt den råa
   brödtexten **före** all tolkning.
2. Beräkna hex-HMAC-SHA256 för
   `<t>\n<METHOD>\n<path and query>\n<body>` med din hemlighet.
3. Avvisa begäran om `t` avviker med mer än 300 sekunder eller om
   resultatet inte matchar `v1` i en jämförelse med konstant tid.

Brödtexter är den kanoniska JSON-serialiseringen (sorterade nycklar, kompakta
avgränsare), och vi signerar exakt de byte vi överför. [Guiden för
verifiering](/sv/guides/verify-webhook-signatures) innehåller den exakta
signerade strängen, ett genomarbetat exempel, kod utan SDK:t och den äldre
headern.

<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>

## Leveranssemantik

Dessa semantiker gäller leveranser till **slutpunkter**. Den äldre webhooken med en enda URL
är ett enda synkront försök utan återförsök, förutom
konfigurationsutbytet för telefonsamtal
[`telephony.incoming`](/sv/webhooks/call-incoming),
som försöks igen en gång.

<AccordionGroup>
  <Accordion title="Återförsök">
    Varje händelse försöks levereras en gång omedelbart. Alla `2xx`-svar
    bekräftar leveransen. Vid alla andra utfall (icke-2xx,
    anslutningsfel, tidsgräns) försöker vi igen efter **1 m, 5 m, 30 m, 2 h, 6 h,
    12 h och 24 h från det första försöket** — 8 försök under
    24 timmar. Om alla försök misslyckas stoppas leveransen och slutpunkten
    markeras med `status="failing"` i
    [webhookslutpunkter](/sv/webhooks/endpoints); vi skickar e-post till organisationens
    ägare och administratörer och visar det i instrumentpanelen. Returnera `2xx` så snart
    nyttolasten har accepterats varaktigt; bearbeta den asynkront.
    Testsändningar från slutpunktens test-API får ett återförsök ungefär en minut efter
    det första försöket och ändrar aldrig slutpunktens status.
  </Accordion>

  <Accordion title="Ordning">
    Leveransordningen sker efter bästa förmåga. I praktiken levererar vi i den
    ordning händelser skapas, men återförsök kan ändra ordningen vid fel.
    Avduplicera och stäm alltid av med `call_id` / objekt-id.
  </Accordion>

  <Accordion title="Dubbletter">
    Leverans sker **minst en gång**: ett återförsök efter ett svar som vi aldrig
    såg kan duplicera en händelse. Varje återförsök har samma
    `event_id`, så lagra bearbetade id:n och hoppa över upprepningar. `event_id` delas
    även mellan ändpunkter — två ändpunkter som prenumererar på samma
    händelse får samma `event_id`.
  </Accordion>

  <Accordion title="Tidsgränser">
    Leveranser till slutpunkter har en tidsgräns på **30 s** per försök. På den
    äldre sökvägen är blockerande förfrågningar som styr beteendet under pågående samtal — 
    konfigurationsutbytet
    [`telephony.incoming` / `web.incoming`](/sv/webhooks/call-incoming) —
    begränsade till **10 s** för ett telefonsamtals första försök och **13 s** för
    hela utbytet inklusive dess enda återförsök, samt till **10 s** för en widgetsessions. Ett långsamt svar fördröjer
    besvarandet av samtalet, så försök svara inom ett par sekunder. [Verktygsanrop](/sv/tools/overview) i webhookläge tillåter 20 s
    som standard, och verktygsdeklarationer kan ange en `timeout` på toppnivå.
  </Accordion>

  <Accordion title="Käll-IP-adresser">
    Utgående webhooks kommer från ThunderPhones IP-intervall i molnet.
    Om din brandvägg kräver en tillåtelselista kontaktar du supporten så
    delar vi de aktuella intervallen.
  </Accordion>
</AccordionGroup>

## Välja mellan äldre och ändpunktsbaserade webhooks

| Funktion | Äldre (`/v1/webhook`) | Slutpunkter (`/v1/developer/webhook-endpoints`) |
|---------|------------------------|----------------------------------------------|
| Antal URL:er | 1 per organisation | Flera per organisation |
| Händelsetäckning | Endast `telephony.*` / `web.*` | Alla 10 händelsetyper |
| Händelsefilter | — | Per slutpunkt |
| Återförsök | Inga, förutom ett för konfigurationsutbytet för telefonsamtal | 8 försök under 24 h |
| Omslag | `type` + `data` | `type` + `data` + `event_id` |
| Rotering av hemlighet | Ersätter en enda hemlighet | Hemlighet per slutpunkt |
| Inaktivera utan att ta bort | `PUT /v1/webhook` med `{"url": ""}` | `status=disabled` |
| Statussynlighet | — | `active` / `disabled` / `failing` |
| Blockerande konfigurationsutbyte | Ja ([`telephony.incoming` / `web.incoming`](/sv/webhooks/call-incoming)) | Aldrig — endast notifieringar |
| Bäst för | Dynamisk samtalskonfiguration | Händelsehantering i produktion |

Nya integrationer bör hantera händelser via ändpunktsbaserade
webhooks. Behåll (eller lägg till) en äldre URL endast om du konfigurerar samtal
dynamiskt när de besvaras eller använder verktygsanrop i webhookläge — dessa
begäran/svar-utbyten körs endast på den äldre sökvägen.

---

## Relaterat

<CardGroup cols={2}>
  <Card title="Händelsekatalog" icon="list" href="/sv/webhooks/events">
    Alla händelsetyper och deras nyttolaster.
  </Card>
  <Card title="Webhook-slutpunkter" icon="bolt" href="/sv/webhooks/endpoints">
    Hantera flera slutpunkter, händelsefilter och hemligheter.
  </Card>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/sv/webhooks/call-incoming">
    Den blockerande begäran som din server måste besvara för att konfigurera samtal.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone" href="/sv/webhooks/call-complete">
    Nyttolast efter samtalet med transkription, inspelning och mätvärden.
  </Card>
</CardGroup>
