---
title: "వెబ్‌హుక్ సంతకాలను ధృవీకరించండి"
description: "ThunderPhone పంపే ప్రతి వెబ్‌హుక్ మరియు టూల్ అభ్యర్థన సంతకం చేయబడుతుంది. ఇక్కడి విధానంతో సంతకాన్ని ఒకసారి ధృవీకరించండి, ఆపై మీరు నడిపే ప్రతి ఎండ్‌పాయింట్‌లో అదే తనిఖీని మళ్లీ ఉపయోగించండి."
---

మీ సర్వర్‌కు మేము పంపే ప్రతి అభ్యర్థన — webhook డెలివరీలు మరియు
tool-endpoint ఇన్‌వొకేషన్లు — `X-ThunderPhone-Signature` హెడర్‌లో
HMAC-SHA256 సంతకాన్ని కలిగి ఉంటుంది. ధృవీకరణను ఒకసారి సరిగ్గా అమలు చేసి,
అదే హెల్పర్‌ను ప్రతి హ్యాండ్లర్‌లో ఉపయోగించండి.

## అల్గారిథమ్

1. **రా** రిక్వెస్ట్ బాడీని చదవండి — మేము మీకు POST చేసిన ఖచ్చితమైన బైట్‌లు.
2. `hmac_sha256(secret, body).hexdigest()`ను గణించండి.
3. `X-ThunderPhone-Signature`తో **స్థిర సమయం**లో పోల్చండి.
   (సాధారణ స్ట్రింగ్ పోలిక టైమింగ్ సమాచారాన్ని బహిర్గతం చేస్తుంది.)

మేము ప్రసారం చేసే ఖచ్చితమైన బైట్‌లకే సంతకం చేస్తాము కాబట్టి, రా బాడీని
ధృవీకరించడం ఎల్లప్పుడూ పనిచేస్తుంది. ఆ బైట్‌లు పేలోడ్ యొక్క **కానానికల్ JSON సీరియలైజేషన్** కూడా —
కీలను అక్షర క్రమంలో అమర్చడం, కాంపాక్ట్ సెపరేటర్‌లు
(స్పేస్‌లు లేకుండా `,` మరియు `:`), UTF-8. మీ ఫ్రేమ్‌వర్క్ పార్స్ చేసిన JSONను మాత్రమే
అందించినప్పుడు, ఇది మీకు పూర్తిగా సమానమైన రెండవ విధానాన్ని అందిస్తుంది:
కానానికల్‌గా మళ్లీ సీరియలైజ్ చేసి, దానికి HMAC వర్తింపజేయండి.

```python
# Equivalent to hashing the raw body:
import json
canonical = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")
```

రా బాడీకి ప్రాధాన్యత ఇవ్వండి — ఇది ఒక దశ తక్కువగా ఉంటుంది మరియు కొన్ని భాషల్లో
JSON సంఖ్యల రౌండ్-ట్రిప్పింగ్ ప్రత్యేకతల ప్రభావానికి లోనుకాదు.

## ఏ సీక్రెట్?

| మూలం | సీక్రెట్ |
|--------|--------|
| [Webhook ఎండ్‌పాయింట్](/te/webhooks/endpoints) (`/v1/developer/webhook-endpoints`) | సృష్టించే సమయంలో ఒక్కసారి తిరిగి ఇచ్చే ప్రతి-ఎండ్‌పాయింట్ `secret` (48 హెక్స్ అక్షరాలు) |
| [లెగసీ సింగిల్-URL webhook](/api-reference/organizations#legacy-single-url-webhook) | `GET /v1/webhook`లో తిరిగి ఇచ్చే ప్రతి-ఆర్గనైజేషన్ `secret` |
| [Tool-endpoint ఇన్‌వొకేషన్](/te/tools/overview) (మీ `endpoint.url`కు నేరుగా చేసే కాల్) | **ఆర్గనైజేషన్-స్థాయి webhook సీక్రెట్** (లెగసీ సింగిల్-URL webhookకు ఉన్నదే) — ప్రతి-ఎండ్‌పాయింట్ సీక్రెట్ కాదు |

సీక్రెట్‌ను మీ సీక్రెట్ మేనేజర్ లేదా env varలో నిల్వ చేయండి — దాన్ని ఎప్పుడూ కమిట్ చేయవద్దు.

## రిఫరెన్స్ అమలులు

ఈ నాలుగూ రా రిక్వెస్ట్ బాడీని ధృవీకరిస్తాయి:

<CodeGroup>
```python Python
import hashlib
import hmac


def verify(body: bytes, signature: str, secret: str) -> bool:
    """Constant-time HMAC-SHA256 verification."""
    expected = hmac.new(
        secret.encode("utf-8"),
        body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature or "")
```

```javascript Node.js
import crypto from "node:crypto";

export function verify(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),
  );
}
```

```go Go
package webhook

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)

func Verify(body []byte, signature, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(body)
    expected := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signature))
}
```

```ruby Ruby
require "openssl"

def verify(body, signature, secret)
  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, body)
  Rack::Utils.secure_compare(expected, signature.to_s)
end
```
</CodeGroup>

## ఫ్రేమ్‌వర్క్-నిర్దిష్ట అనుసంధానం

<CodeGroup>
```python FastAPI
from fastapi import FastAPI, HTTPException, Request

app = FastAPI()

@app.post("/thunderphone-webhook")
async def hook(request: Request):
    body = await request.body()           # raw bytes, NOT request.json()
    sig = request.headers.get("X-ThunderPhone-Signature", "")
    if not verify(body, sig, SECRET):
        raise HTTPException(status_code=401)

    import json
    event = json.loads(body)
    # … dispatch on event["type"] …
    return {"ok": True}
```

```javascript Express
import express from "express";

const app = express();

app.post(
  "/thunderphone-webhook",
  // IMPORTANT: parse as raw; do NOT use express.json() here.
  express.raw({ type: "application/json" }),
  (req, res) => {
    const sig = req.header("X-ThunderPhone-Signature") || "";
    if (!verify(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);
  },
);
```

```python Django
import json

from django.http import JsonResponse, HttpResponseForbidden
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST


@csrf_exempt
@require_POST
def hook(request):
    body = request.body  # raw bytes
    sig = request.headers.get("X-ThunderPhone-Signature", "")
    if not verify(body, sig, SECRET):
        return HttpResponseForbidden("invalid signature")
    event = json.loads(body)
    # … dispatch on event["type"] …
    return JsonResponse({"ok": True})
```
</CodeGroup>

## టూల్ కాల్‌లను ధృవీకరించడం

ఏజెంట్ మీ [ఫంక్షన్ టూల్స్](/te/tools/overview)లో ఒకదాన్ని నేరుగా
ఇన్వోక్ చేసినప్పుడు (ఆ టూల్‌కు `endpoint` ఉంటుంది), అభ్యర్థన మీ
కాన్ఫిగర్ చేసిన `endpoint.headers`తో పాటు రెండు ThunderPhone హెడర్‌లను కలిగి ఉంటుంది:

- `X-ThunderPhone-Call-ID` — కొనసాగుతున్న కాల్ యొక్క సంఖ్యా ఐడి.
- `X-ThunderPhone-Signature` — ఖచ్చితమైన అభ్యర్థన-బాడీ బైట్‌లపై మీ
  **సంస్థ-స్థాయి వెబ్‌హుక్ సీక్రెట్**తో కీ చేసిన HMAC-SHA256.

అదే `verify()` హెల్పర్ మార్పులు లేకుండానే పనిచేస్తుంది, అయితే రెండు ప్రత్యేకతలు ఉన్నాయి:

1. **`GET` / `DELETE` టూల్‌లకు బాడీ ఉండదు.** ఆర్గ్యుమెంట్‌లు క్వెరీ
   పారామీటర్‌లుగా వెళ్తాయి మరియు సిగ్నేచర్ **ఖాళీ బైట్
   స్ట్రింగ్**పై గణించబడుతుంది — కాబట్టి `verify(b"", sig, secret)` (Python) లేదా
   `verify(Buffer.alloc(0), sig, secret)` (Node) ఉపయోగించండి. క్వెరీ
   స్ట్రింగ్‌ను హ్యాష్ చేయవద్దు.
2. **లెగసీ వెబ్‌హుక్ కాన్ఫిగర్ చేయని సంస్థలకు సంస్థ సీక్రెట్ ఉండదు.** ఆ
   సందర్భంలో టూల్ కాల్‌లు `X-ThunderPhone-Call-ID`ను మాత్రమే కలిగి ఉంటాయి; సిగ్నేచర్
   హెడర్ ఉండదు. సైనింగ్ సీక్రెట్ పొందడానికి లెగసీ వెబ్‌హుక్‌ను
   (`PUT /v1/webhook`) కాన్ఫిగర్ చేయండి లేదా `endpoint.headers` ద్వారా మీ స్వంత హెడర్‌తో
   టూల్ కాల్‌లను ప్రమాణీకరించండి.

```python
@app.post("/tools/search-appointments")
async def tool(request: Request):
    body = await request.body()  # b"" for GET/DELETE tools
    sig = request.headers.get("X-ThunderPhone-Signature", "")
    call_id = request.headers.get("X-ThunderPhone-Call-ID", "")
    if not verify(body, sig, ORG_WEBHOOK_SECRET):
        raise HTTPException(status_code=401)
    args = json.loads(body)
    ...
```

వెబ్‌హుక్-**మోడ్** టూల్ డిస్పాచ్ (`endpoint` లేని టూల్‌లు, మీ సంస్థ
వెబ్‌హుక్‌కు `telephony.tool` / `web.tool`గా పంపబడతాయి) సాధారణ సైన్డ్ వెబ్‌హుక్ —
పైన ఉన్న ప్రామాణిక విధానం వర్తిస్తుంది. రెండు అభ్యర్థన ఆకృతుల కోసం
[ఫంక్షన్ టూల్స్](/te/tools/overview) చూడండి.

## సాధారణ సమస్యలు

<AccordionGroup>
  <Accordion title="డిఫాల్ట్ ఫార్మాటింగ్‌తో మళ్లీ సీరియలైజ్ చేయడం">
    మీ JSON లైబ్రరీ డిఫాల్ట్‌లతో బాడీని పార్స్ చేసి మళ్లీ డంప్ చేయడం
    (`,` / `:` తర్వాత ఖాళీలు, చొప్పింపు-క్రమంలో కీలు) భిన్నమైన
    బైట్‌లను ఉత్పత్తి చేసి HMACను విఫలం చేస్తుంది. రా బాడీని ధృవీకరించండి — లేదా మీరు
    తప్పనిసరిగా మళ్లీ సీరియలైజ్ చేయాల్సి ఉంటే, మా కానానికల్ రూపానికి ఖచ్చితంగా సరిపోల్చండి:
    క్రమబద్ధీకరించిన కీలు, కాంపాక్ట్ సెపరేటర్లు, UTF-8.
  </Accordion>

  <Accordion title="ఫ్రేమ్‌వర్క్ JSONను స్వయంచాలకంగా పార్స్ చేస్తుంది">
    Express యొక్క `express.json()` మిడిల్‌వేర్ బాడీ స్ట్రీమ్‌ను వినియోగిస్తుంది
    మరియు మీరు రా బైట్‌లను కోల్పోతారు. వెబ్‌హుక్
    రూట్‌లో ప్రత్యేకంగా `express.raw()` ఉపయోగించండి లేదా ప్రీ-మిడిల్‌వేర్‌లో రా బాడీని బఫర్ చేయండి.
    NestJS / Koa కోసం కూడా ఇదే వర్తిస్తుంది — వాటి "రా బాడీ" డాక్యుమెంటేషన్‌ను చూడండి.
  </Accordion>

  <Accordion title="టైమింగ్‌కు సురక్షితం కాని పోలిక">
    JSలో `expected === signature` లేదా Pythonలో `expected == signature`
    టైమింగ్-వేరియబుల్ పోలికలు. వరుసగా `crypto.timingSafeEqual`
    లేదా `hmac.compare_digest` ఉపయోగించండి. పనితీరు తేడా
    ఏమాత్రం ఉండదు.
  </Accordion>

  <Accordion title="టూల్ ఎండ్‌పాయింట్‌లకు తప్పు సీక్రెట్">
    డైరెక్ట్ టూల్-ఎండ్‌పాయింట్ కాల్‌లు **సంస్థ-స్థాయి వెబ్‌హుక్
    సీక్రెట్** (`GET /v1/webhook`)తో సంతకం చేయబడతాయి — 
    `/v1/developer/webhook-endpoints`లోని ఏ ఒక్కో ఎండ్‌పాయింట్ సీక్రెట్‌తో కాదు. అదే `verify()`
    ఫంక్షన్‌ను మళ్లీ ఉపయోగించండి, కానీ టూల్ రూట్‌లలో దానికి సంస్థ సీక్రెట్‌ను అందిస్తున్నారని నిర్ధారించుకోండి.
  </Accordion>

  <Accordion title="GET/DELETE టూల్‌లలో క్వెరీ స్ట్రింగ్‌ను హ్యాష్ చేయడం">
    బాడీ లేని టూల్ మెథడ్‌ల కోసం సిగ్నేచర్ ఖాళీ బైట్
    స్ట్రింగ్‌ను కవర్ చేస్తుంది, దీంతో ఒకే సార్వత్రిక విధానం ఉంటుంది: రా రిక్వెస్ట్ బాడీ ఏదైనా సరే దానికి HMAC చేయండి.
    URL లేదా క్వెరీ స్ట్రింగ్‌ను హ్యాష్ చేస్తే ఎప్పటికీ సరిపోలదు.
  </Accordion>

  <Accordion title="సరిపోలనప్పుడు 401ని తిరిగి ఇవ్వకపోవడం">
    ధృవీకరణ విఫలమైనప్పుడు 200ని తిరిగి ఇవ్వడం హ్యాండ్లర్‌ను రీప్లే
    లక్ష్యంగా మారుస్తుంది. ధృవీకరణ విఫలమైతే ఎల్లప్పుడూ 2xx కాని ప్రతిస్పందన ఇవ్వండి.
  </Accordion>
</AccordionGroup>

---

## తదుపరి దశలు

<CardGroup cols={2}>
  <Card title="వెబ్‌హుక్‌ల అవలోకనం" icon="bolt" href="/te/webhooks/overview">
    డెలివరీ సెమాంటిక్స్, మళ్లీ ప్రయత్నాలు, సోర్స్ IPలు.
  </Card>
  <Card title="వెబ్‌హుక్ ఎండ్‌పాయింట్‌లు" icon="plug" href="/te/webhooks/endpoints">
    బహుళ URLలను నిర్వహించండి, సీక్రెట్‌లను రొటేట్ చేయండి.
  </Card>
  <Card title="ఫంక్షన్ టూల్స్" icon="screwdriver-wrench" href="/te/tools/overview">
    రెండు టూల్-ఇన్వొకేషన్ మార్గాలు మరియు వాటి రిక్వెస్ట్ ఆకారాలు.
  </Card>
  <Card title="టూల్ ఇంటిగ్రేషన్‌లు" icon="wrench" href="/te/guides/build-tool-integration">
    పూర్తి టూల్-ఆధారిత ఇంటిగ్రేషన్‌ను మొదటి నుంచి చివరి వరకు రూపొందించండి.
  </Card>
</CardGroup>
