---
title: "Muhtasari wa Webhook"
description: "Jinsi ThunderPhone inavyowasilisha matukio ya wakati halisi, jinsi ya kuthibitisha sahihi, na jinsi miundo ya urithi na inayotegemea endpoint ya uwasilishaji inavyolinganishwa."
---

ThunderPhone hutuma maombi ya HTTP `POST` kwa seva yako matukio
yanapotokea wakati wa simu — simu inayoingia inaanza, simu inaisha, utekelezaji
wa upimaji unakamilika, tahadhari inawashwa, na kadhalika. Kuna **miundo
miwili ya uwasilishaji**:

<CardGroup cols={2}>
  <Card title="Vituo vya webhook (vinavyopendekezwa)" icon="bolt" href="/sw/webhooks/endpoints">
    URL nyingi, siri kwa kila kituo, vichujio vya matukio kwa kila kituo,
    na majaribio upya ya kiotomatiki.
    Dhibiti kupitia `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints`.
  </Card>
  <Card title="Webhook ya urithi ya URL moja" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    URL moja kwa kila shirika. Hubeba matukio ya mzunguko wa maisha wa simu, ikijumuisha
    ubadilishanaji wa usanidi **wa kuzuia**. Dhibitiwa kupitia `GET/PUT /v1/webhook`.
  </Card>
</CardGroup>

Aina zote kumi za matukio katika [katalogi ya matukio](/sw/webhooks/events)
huwasilishwa kupitia vituo vya webhook. Matukio sita ya mzunguko wa maisha wa simu
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) **pia** hutumwa kwenye
webhook ya urithi ya URL moja — ikiwa una URL ya urithi na kituo
kinacholingana, unapokea tukio kwenye njia **zote mbili**. Tabia ya kuzuia
([ubadilishanaji wa usanidi wa `telephony.incoming` / `web.incoming`](/sw/webhooks/call-incoming)
na [utumaji wa zana](/sw/tools/overview) wa hali ya webhook)
upo kwenye njia ya urithi pekee; kila uwasilishaji wa kituo ni
arifa inayotumwa bila kusubiri jibu.

## Muundo wa payload

Uwasilishaji wa vituo ni objekti ya JSON yenye `data`, `event_id`, na
`type`:

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

`event_id` ni ya kipekee kwa kila tukio linalotolewa. Inafanana katika majaribio upya
**na** katika kila kituo kinachopokea tukio — ondoa nakala kwa kuitumia.

Webhook ya urithi ya URL moja hutuma `type` na `data` zilezile lakini
**bila** `event_id`:

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

Katika usafirishaji wa mtandao, kila body husasishwa kwa mpangilio kanoniki — funguo hupangwa
kialfabeti, bila nafasi nyeupe, UTF-8. Mifano iliyopangwa kwa urahisi wa kusoma katika
nyaraka hizi ni kwa ajili ya usomaji pekee.

Tazama [Katalogi ya matukio](/sw/webhooks/events) kwa orodha kamili ya aina za matukio
na sehemu za payload.

## Uthibitishaji wa saini

Kila ombi hubeba saini ya HMAC-SHA256 kwenye **mwili ghafi wa
ombi** katika kichwa cha `X-ThunderPhone-Signature`. Ufunguo wa kutia saini ni
`secret` ya endpoint (au `secret` ya webhook ya kiwango cha shirika lako kwa
usafirishaji wa zamani).

### Hatua

1. Soma mwili ghafi wa ombi **kabla** ya uchanganuzi wowote.
2. Kokotoa `hmac_sha256(secret, body).hexdigest()`.
3. Linganisha kwa muda usiobadilika na kichwa cha `X-ThunderPhone-Signature`.

Tunatia saini byte zilezile tunazotuma, na byte hizo ni
uundaji wa JSON wa kanoni (funguo zilizopangwa, vitenganishi vifupi). Hivyo,
uthibitishaji dhidi ya mwili ghafi hufanya kazi kila mara — na ikiwa fremu yako
inakupa JSON iliyochanganuliwa pekee, kuiunda upya kwa funguo zilizopangwa na
vitenganishi vifupi huzalisha byte zinazofanana. Mbinu zote mbili zimeelezwa
katika [mwongozo wa uthibitishaji](/sw/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>

## Semantiki za uwasilishaji

Semantiki hizi zinatumika kwa uwasilishaji wa **endpoint**. Webhook ya urithi ya URL moja ni jaribio moja la kisawazishaji lisilo na majaribio ya kurudia.

<AccordionGroup>
  <Accordion title="Majaribio ya kurudia">
    Kila tukio hujaribiwa mara moja mara moja. Jibu lolote la `2xx`
    hukubali uwasilishaji. Kwa matokeo mengine yoyote (yasiyo ya 2xx,
    hitilafu ya muunganisho, muda kuisha) tunajaribu tena baada ya **dakika 1, dakika 5, dakika 30, saa 2, saa 6,
    saa 12, na saa 24 tangu jaribio la kwanza** — majaribio 8 ndani ya
    saa 24. Ikiwa kila jaribio litashindwa, uwasilishaji husimama na endpoint
    huwekwa alama `status="failing"` katika
    [endpoint za webhook](/sw/webhooks/endpoints). Rudisha `2xx` punde tu
    payload inapokubaliwa kwa uhifadhi wa kudumu; ichakate kwa usawazishaji wa nyuma.
  </Accordion>

  <Accordion title="Mpangilio">
    Mpangilio wa uwasilishaji hufanywa kwa juhudi bora. Kwa kawaida tunawasilisha kwa
    mpangilio ambao matukio hutolewa, lakini majaribio ya kurudia yanaweza kubadilisha mpangilio kunapotokea hitilafu.
    Daima ondoa nakala rudufu na linganisha kwa `call_id` / id ya kitu.
  </Accordion>

  <Accordion title="Nakala rudufu">
    Uwasilishaji ni **angalau mara moja**: jaribio la kurudia baada ya jibu ambalo hatukuliona
    linaweza kurudia tukio. Kila jaribio la kurudia hubeba `event_id` ileile,
    hivyo hifadhi id zilizochakatwa na ruka marudio. `event_id` pia
    hushirikiwa kati ya endpoint — endpoint mbili zilizojiandikisha kwa
    tukio lilelile hupokea `event_id` ileile.
  </Accordion>

  <Accordion title="Muda kuisha">
    Uwasilishaji wa endpoint una muda wa kuisha wa **sekunde 30** kwa kila jaribio. Kwenye
    njia ya urithi, maombi yanayozuia ambayo huendesha tabia ya simu mubashara —
    ubadilishanaji wa usanidi wa [`telephony.incoming` / `web.incoming`](/sw/webhooks/call-incoming)
    — huisha muda baada ya **sekunde 10**, lakini jibu la polepole huchelewesha kupokelewa kwa simu,
    hivyo lenga kujibu ndani ya sekunde chache. [Utumaji wa zana](/sw/tools/overview) katika hali ya webhook
    huruhusu sekunde 20 kwa chaguo-msingi, na matamko ya zana yanaweza kuweka `timeout` ya kiwango cha juu.
  </Accordion>

  <Accordion title="IP za chanzo">
    Webhook zinazotoka hutoka kwenye safu ya IP za wingu la ThunderPhone.
    Ikiwa firewall yako inahitaji orodha ya kuruhusu, wasiliana na usaidizi nasi
    tutashiriki safu za sasa.
  </Accordion>
</AccordionGroup>

## Kuchagua kati ya webhook za urithi na zinazotegemea endpoint

| Kipengele | Urithi (`/v1/webhook`) | Endpoint (`/v1/developer/webhook-endpoints`) |
|---------|------------------------|----------------------------------------------|
| Idadi ya URL | 1 kwa kila org | Nyingi kwa kila org |
| Ufunikaji wa matukio | `telephony.*` / `web.*` pekee | Aina zote 10 za matukio |
| Kichujio cha matukio | — | Kwa kila endpoint |
| Majaribio ya kurudia | Hakuna | Majaribio 8 ndani ya saa 24 |
| Bahasha | `type` + `data` | `type` + `data` + `event_id` |
| Mzunguko wa siri | Hubadilisha siri moja | Siri kwa kila endpoint |
| Lemaza bila kufuta | `PUT /v1/webhook` yenye `{"url": ""}` | `status=disabled` |
| Mwonekano wa hali | — | `active` / `disabled` / `failing` |
| Ubadilishanaji wa usanidi unaozuia | Ndiyo ([`telephony.incoming` / `web.incoming`](/sw/webhooks/call-incoming)) | Kamwe — arifa pekee |
| Bora kwa | Usanidi wa simu unaobadilika | Utumiaji wa matukio katika uzalishaji |

Miunganisho mipya inapaswa kutumia matukio kupitia webhook zinazotegemea
endpoint. Hifadhi (au ongeza) URL ya urithi tu ikiwa unasanidi simu
kwa kubadilika wakati wa kupokea simu au unatumia utumaji wa zana katika hali ya webhook — ubadilishanaji huo
wa ombi/jibu huendeshwa kwenye njia ya urithi pekee.

---

## Husika

<CardGroup cols={2}>
  <Card title="Katalogi ya matukio" icon="list" href="/sw/webhooks/events">
    Aina zote za matukio na payload zake.
  </Card>
  <Card title="Endpoint za webhook" icon="bolt" href="/sw/webhooks/endpoints">
    Dhibiti endpoint nyingi, vichujio vya matukio, na siri.
  </Card>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/sw/webhooks/call-incoming">
    Ombi linalozuia ambalo seva yako lazima ijibu ili kusanidi simu.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone" href="/sw/webhooks/call-complete">
    Payload ya baada ya simu yenye nakala ya mazungumzo, rekodi, na vipimo.
  </Card>
</CardGroup>
