> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Prezentare generală a webhookurilor

> Cum livrează ThunderPhone evenimente în timp real, cum să verificați semnăturile și cum se compară modelele de livrare moștenit și bazat pe endpointuri.

ThunderPhone trimite solicitări HTTP `POST` către serverul dumneavoastră atunci când se
întâmplă lucruri în timpul unui apel — începe un apel de intrare, se încheie un apel, se finalizează
o rulare de evaluare, se declanșează o alertă și așa mai departe. Există **două modele
de livrare**:

<CardGroup cols={2}>
  <Card title="Endpoint-uri webhook (recomandat)" icon="bolt" href="/ro/webhooks/endpoints">
    Mai multe URL-uri, secrete per endpoint, filtre de evenimente per endpoint
    și reîncercări automate.
    Gestionați prin `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints`.
  </Card>

  <Card title="Webhook legacy cu un singur URL" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    Un URL per organizație. Include evenimentele ciclului de viață al apelului, inclusiv
    schimburile de configurare **blocante**. Gestionat la `GET/PUT /v1/webhook`.
  </Card>
</CardGroup>

Toate cele zece tipuri de evenimente din [catalogul de evenimente](/ro/webhooks/events) sunt
livrate prin endpoint-uri webhook. Cele șase evenimente ale ciclului de viață al apelului
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) sunt trimise **și** către
webhook-ul legacy cu un singur URL — dacă aveți atât un URL legacy, cât și un
endpoint corespunzător, primiți evenimentul pe **ambele** căi. Comportamentul
blocant (schimbul de configurare [`telephony.incoming` / `web.incoming`](/ro/webhooks/call-incoming)
și [dispecerizarea instrumentelor](/ro/tools/overview) în modul webhook)
există exclusiv pe calea legacy; fiecare livrare către endpoint este o
notificare fire-and-forget.

## Formatul încărcăturii

Livrările către endpoint-uri sunt un obiect JSON cu `data`, `event_id` și
`type`:

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

`event_id` este unic pentru fiecare eveniment emis. Este identic între reîncercări
**și** între toate endpoint-urile care primesc evenimentul — eliminați duplicatele pe baza acestuia.

Webhook-ul legacy cu un singur URL trimite același `type` și `data`, dar
**fără** `event_id`:

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

În tranzit, fiecare corp este serializat canonic — cheile sunt sortate
alfabetic, fără spații albe, în UTF-8. Exemplele formatate pentru lizibilitate din
această documentație sunt doar pentru claritate.

Consultați [catalogul de evenimente](/ro/webhooks/events) pentru lista completă a tipurilor de
evenimente și a câmpurilor încărcăturii.

## Verificarea semnăturii

Fiecare solicitare include o semnătură HMAC-SHA256 calculată asupra **corpului brut al solicitării** în antetul `X-ThunderPhone-Signature`. Cheia de semnare este `secret` al endpointului (sau `secret` al webhookului la nivel de organizație pentru livrările vechi).

### Pași

1. Citiți corpul brut al solicitării **înainte** de orice analiză.
2. Calculați `hmac_sha256(secret, body).hexdigest()`.
3. Comparați în timp constant cu antetul `X-ThunderPhone-Signature`.

Semnăm exact octeții pe care îi transmitem, iar aceștia reprezintă serializarea JSON canonică (chei sortate, separatori compacți). Prin urmare, verificarea pe corpul brut funcționează întotdeauna — iar dacă frameworkul dumneavoastră vă oferă doar JSON-ul analizat, reserializarea acestuia cu chei sortate și separatori compacți produce octeți identici. Ambele metode sunt prezentate în [ghidul de verificare](/ro/guides/verify-webhook-signatures).

<CodeGroup>
  ```python Python theme={null}
  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) theme={null}
  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>

## Semantica livrării

Această semantică se aplică livrărilor către **endpoint-uri**. Webhookul
moștenit cu un singur URL constă într-o singură încercare sincronă, fără reîncercări.

<AccordionGroup>
  <Accordion title="Reîncercări">
    Fiecare eveniment este încercat imediat o dată. Orice răspuns `2xx`
    confirmă livrarea. Pentru orice alt rezultat (non-2xx,
    eroare de conexiune, expirare a timpului), reîncercăm la **1 m, 5 m, 30 m, 2 h, 6 h,
    12 h și 24 h după prima încercare** — 8 încercări pe parcursul a
    24 de ore. Dacă toate încercările eșuează, livrarea se oprește, iar endpoint-ul
    este marcat cu `status="failing"` în
    [endpoint-uri webhook](/ro/webhooks/endpoints). Returnați `2xx` imediat ce
    payloadul este acceptat durabil; procesați asincron.
  </Accordion>

  <Accordion title="Ordine">
    Ordinea livrărilor este realizată în limita posibilului. În practică, livrăm în
    ordinea în care sunt emise evenimentele, însă reîncercările pot schimba ordinea în caz de eșec.
    Deduplicați întotdeauna și efectuați reconcilierea după `call_id` / id-ul obiectului.
  </Accordion>

  <Accordion title="Duplicate">
    Livrarea este **cel puțin o dată**: o reîncercare după un răspuns pe care nu l-am
    primit poate duplica un eveniment. Fiecare reîncercare include același
    `event_id`, așadar stocați id-urile procesate și ignorați repetările. `event_id` este
    partajat și între endpoint-uri — două endpoint-uri abonate la același eveniment primesc același `event_id`.
  </Accordion>

  <Accordion title="Expirări ale timpului">
    Livrările către endpoint-uri au o expirare a timpului de **30 s** pentru fiecare încercare. Pe
    calea moștenită, cererile blocante care determină comportamentul apelurilor live — schimbul de
    configurare [`telephony.incoming` / `web.incoming`](/ro/webhooks/call-incoming) —
    expiră după **10 s**, însă un răspuns lent întârzie preluarea apelului, deci urmăriți să
    răspundeți în câteva secunde. [Executarea instrumentelor](/ro/tools/overview) în modul webhook permite 20 s.
  </Accordion>

  <Accordion title="IP-uri sursă">
    Webhookurile trimise provin din intervalul de IP-uri cloud al ThunderPhone.
    Dacă firewallul dumneavoastră necesită o listă de permisiuni, contactați suportul și vă vom
    comunica intervalele curente.
  </Accordion>
</AccordionGroup>

## Alegerea între webhookurile moștenite și cele bazate pe endpoint-uri

| Funcționalitate               | Moștenit (`/v1/webhook`)                                                 | Endpoint-uri (`/v1/developer/webhook-endpoints`) |
| ----------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------ |
| Număr de URL-uri              | 1 per organizație                                                        | Mai multe per organizație                        |
| Acoperirea evenimentelor      | Numai `telephony.*` / `web.*`                                            | Toate cele 10 tipuri de evenimente               |
| Filtru de evenimente          | —                                                                        | Per endpoint                                     |
| Reîncercări                   | Niciuna                                                                  | 8 încercări în 24 h                              |
| Plic                          | `type` + `data`                                                          | `type` + `data` + `event_id`                     |
| Rotirea secretului            | Înlocuiește secretul unic                                                | Secret per endpoint                              |
| Dezactivare fără ștergere     | —                                                                        | `status=disabled`                                |
| Vizibilitatea stării          | —                                                                        | `active` / `disabled` / `failing`                |
| Schimb de configurare blocant | Da ([`telephony.incoming` / `web.incoming`](/ro/webhooks/call-incoming)) | Niciodată — numai notificări                     |
| Recomandat pentru             | Configurarea dinamică a apelurilor                                       | Consumul de evenimente în producție              |

Integrările noi trebuie să consume evenimente prin webhookuri bazate pe
endpoint-uri. Păstrați (sau adăugați) un URL moștenit numai dacă configurați apelurile
dinamic la momentul preluării sau utilizați executarea instrumentelor în modul webhook — aceste
schimburi cerere/răspuns rulează numai pe calea moștenită.

***

## Asociate

<CardGroup cols={2}>
  <Card title="Catalog de evenimente" icon="list" href="/ro/webhooks/events">
    Toate tipurile de evenimente și payloadurile acestora.
  </Card>

  <Card title="Endpoint-uri webhook" icon="bolt" href="/ro/webhooks/endpoints">
    Gestionați mai multe endpoint-uri, filtre de evenimente și secrete.
  </Card>

  <Card title="telephony.incoming / web.incoming" icon="phone" href="/ro/webhooks/call-incoming">
    Cererea blocantă la care serverul dumneavoastră trebuie să răspundă pentru a configura apelurile.
  </Card>

  <Card title="telephony.complete / web.complete" icon="phone" href="/ro/webhooks/call-complete">
    Payload post-apel cu transcriere, înregistrare și metrici.
  </Card>
</CardGroup>
