---
title: "Dinamična konfiguracija za posamezen klic"
description: "Za vsak dohodni klic posebej izberite odgovarjajočega agenta ali prepišite njegov poziv in nastavitve na podlagi logike po meri v spletnem kavlju, ki ga upravljate vi."
---

Vsaki telefonski številki in ključu za objavo je privzeto dodeljen statični agent. Ko potrebujete prilagoditev **za posameznega klicatelja** ali **za posameznega obiskovalca** — usmerjanje VIP, kontekst prijavljenega uporabnika, A/B-preizkuse pozivov — preklopite v način webhook in prepustite odločitev strežniku.

## Kako deluje

1. Naročite se na dogodek [`telephony.incoming`](/sl/webhooks/events)
   (telefon) ali [`web.incoming`](/sl/webhooks/events) (gradnik).
   Oba sta **blokirajoča** webhooka: ThunderPhone pred nadaljevanjem klica
   na vaš odgovor čaka do 10 sekund.
2. ThunderPhone vam pošlje `{call_id, from_number, to_number}` (seje gradnika
   namesto številk vsebujejo polja, specifična za gradnik — glejte
   [shemo zahteve](/sl/webhooks/call-incoming)).
3. Vaš strežnik odgovori s konfiguracijo agenta (poziv, glas,
   izdelek, orodja). ThunderPhone to konfiguracijo uporabi za klic.
4. Če vrnete `{}`, pride do časovne omejitve ali napake, se kot nadomestna možnost
   uporabi statično dodeljeni agent. Varna privzeta nastavitev.

<Note>
  Deluje enako za telefonske klice (`telephony.incoming`) in seje
  gradnika (`web.incoming`), ne glede na to, ali so dostavljeni v končno
  točko webhooka ali starejšemu webhooku z enim URL-jem.
</Note>

<Warning>
  **Pri klicih, konfiguriranih neposredno prek webhooka, se obvestilo
  ThunderPhone o soglasju ne predvaja.** Ta pot obide obvestilo na ravni
  agenta ob začetku klica in je izrecno izključena iz okvira ThunderPhone
  za obvestila o soglasju (Pogoji uporabe, razdelek »Snemanje in soglasje«).
  Vaša organizacija je odgovorna za vsa obvestila in soglasja glede snemanja,
  spremljanja, sodelovanja AI in identifikacije klicatelja pri teh klicih.
  Zagotovite jih v svojem poteku — na primer v uvodnem scenariju poziva —
  preden omogočite neposredni način webhooka. Odgovor webhooka, ki se sklicuje na
  shranjeni `agent_id`, uporablja običajno politiko snemanja in razkritij tega agenta.
</Warning>

## 1. Konfigurirajte cilj webhooka

<Tabs>
<Tab title="Telefonski klici">
Za telefonske številke naročite svojo končno točko na `telephony.incoming`:

```bash
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":  "Prod call-incoming",
    "url":    "https://example.com/thunderphone/incoming",
    "events": ["telephony.incoming"]
  }'
```

Odgovor vključuje enkratni `secret` — shranite ga; uporabili ga boste
za preverjanje podpisa.
</Tab>
<Tab title="Spletni gradnik">
Za seje gradnika ustvarite ključ za objavo v `mode="webhook"`
z vdelanim URL-jem vaše končne točke:

```bash
curl -X POST https://api.thunderphone.com/v1/publishable-key \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name":            "Dynamic widget",
    "mode":            "webhook",
    "webhook_url":     "https://example.com/thunderphone/widget-incoming",
    "allowed_domains": ["example.com"]
  }'
```

Gradnik bo ob vsakem začetku seje na ta URL poslal zahtevo POST.
</Tab>
</Tabs>

## 2. Implementirajte obdelovalnik

Tri osnovna pravila:

- **Preverite podpis** pri vsaki zahtevi (glejte
  [Preverjanje podpisov webhookov](/sl/guides/verify-webhook-signatures)).
  Tega ne preskočite v razvojnem okolju — enkrat pravilno nastavite in znova uporabite.
- **Odgovorite hitro**. Deset sekund je stroga omejitev, vsaka sekunda pa je
  tišina za klicatelja. Po potrebi izvedite poizvedbe v zbirki podatkov, vendar
  ne kličite nadaljnjih LLM-jev sinhrono — če želite dinamično ustvarjanje pozivov,
  jih vnaprej izračunajte in predpomnite.
- **Urejeno uporabite nadomestno rešitev**. Vsako nepričakovano stanje naj vrne `{}`, da
  statično dodeljeni agent obravnava klic.

<CodeGroup>
```python FastAPI
import hashlib
import hmac
import json
import os

from fastapi import FastAPI, HTTPException, Request

app = FastAPI()
SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]

def verify(body: bytes, sig: str) -> bool:
    expected = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig or "")

@app.post("/thunderphone/incoming")
async def incoming(request: Request):
    body = await request.body()
    if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
        raise HTTPException(401)

    event = json.loads(body)
    if event["type"] not in ("telephony.incoming", "web.incoming"):
        return {}  # fall back to default

    caller = event["data"]["from_number"]
    # Cheap DB lookup: is this a known VIP?
    customer = lookup_customer(caller)
    if customer and customer.tier == "vip":
        return {
            "prompt":  f"You are a VIP concierge for {customer.name}. Be proactive…",
            "voice":   "john",
            "product": "storm-base",
        }
    return {}  # default agent handles non-VIPs

def lookup_customer(phone: str):
    # ... your CRM integration ...
    pass
```

```javascript Express
import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;

function verify(body, sig) {
  const expected = crypto.createHmac("sha256", SECRET).update(body).digest("hex");
  return sig &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}

app.post(
  "/thunderphone/incoming",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
      return res.sendStatus(401);
    }
    const event = JSON.parse(req.body.toString("utf8"));

    const IMPORTANT_TYPES = new Set([
      "telephony.incoming",
      "web.incoming",
    ]);
    if (!IMPORTANT_TYPES.has(event.type)) return res.json({});

    const customer = await lookupCustomer(event.data.from_number);
    if (customer?.tier === "vip") {
      return res.json({
        prompt:  `You are a VIP concierge for ${customer.name}. Be proactive…`,
        voice:   "john",
        product: "storm-base",
      });
    }
    res.json({}); // fall back to default agent
  },
);
```
</CodeGroup>

## 3. Shema odgovora

Telo odgovora se natančno ujema s
[ shemo odgovora za dohodni klic](/sl/webhooks/call-incoming).
Pogosto uporabljena polja:

| Polje | Vrsta | Opis |
|-------|------|-------------|
| `prompt` | niz (obvezno) | Sistemski poziv za agenta |
| `voice` | niz (obvezno) | ID glasu iz [`GET /v1/voices`](/api-reference/agents#voices) |
| `product` | niz | Privzeto je `spark` |
| `background_track` | niz \| null | ID ambientalnega zvoka |
| `acknowledgement_prompt_mode` | niz | `auto` ali `manual` (samo Storm s potrditvijo) |
| `acknowledgement_prompt` | niz | Obvezno, kadar je način `manual` |
| `tools` | polje | Vdelane sheme funkcijskih orodij — glejte [Funkcijska orodja](/sl/tools/overview) |

<Note>
  Vrstni red govorjenja za posamezen klic in `max_hold_seconds` nista na voljo v
  odgovoru webhooka. Nastavite ju pri
  [agentu](/api-reference/agents), na katerega se sklicujete.
</Note>

### Obdržite shranjenega agenta in posredujte spremenljivke

Vrnite `{"agent_id": 12, "variables": {"name": "Ada"}}`, da uporabite shranjenega
agenta te organizacije s podatki za posamezen klic. Njegov poziv lahko vsebuje
`{{name}}` ali `{{name|Friend}}`. Spremenljivke webhooka se združijo prek
spremenljivk na ravni zahteve; vrednost null uporabi privzeto vrednost označbe
ali prazno besedilo, če ni navedena nobena. Končne vrednosti in nerazrešena imena
so prikazani v podrobnostih klica in webhookih ob zaključku. Odgovori shranjenega
agenta sprejemajo samo `agent_id` in `variables`. Če je prisoten `prompt`,
odgovor uporabi vdelano konfiguracijo in prezre `agent_id` (vključno z
metapodatki null ali neceloštevilskimi metapodatki); vdelani poziv mora še vedno
biti veljaven. Odgovori z vdelano konfiguracijo lahko vključujejo tudi
`variables`. Odgovori shranjenega agenta uporabljajo uvedeno A/B-razdelitev
agenta pri telefonskih klicih in klicih gradnika, nato pa upodobijo spremenljivke.
Za omejitve in podporo API-ja sej glejte [spremenljivke klica](/sl/guides/call-variables).
Konfiguracija blokiranja izhaja iz podedovanega URL-ja telefonske številke oziroma
organizacije ali ključa gradnika v načinu webhooka; dohodni dogodki sistema
končne točke so samo obvestila.

## Vzorci

### Kontekst prijavljenega uporabnika

V gradnikih v načinu webhooka stran obiskovalca že ve, kdo je
obiskovalec. Pokličite svoj webhook s parametrom poizvedbenega niza, ki ga SDK
gradnika posreduje naprej (`?customer_id=123`), in stranko poiščite na strežniški
strani.

### Uvajanje pozivov A/B

Preden to sami implementirate, upoštevajte, da ima ThunderPhone vgrajeno
funkcijo [Poskusi](/sl/guides/concepts)
(`/dashboard/experiments` in zavihek **A/B** v gradniku agenta), ki
določa različice, razdeli promet in primerja rezultate za posamezno različico —
webhook ni potreben.

Če vseeno potrebujete nadzor na strani webhooka: zgostite `call_id` → segment;
za `0..49` uporabite poziv A, za `50..99` pa poziv B. Izbrani segment
zabeležite v lastni zbirki podatkov in ga pozneje povežite z oceno
zaključenega klica.

### Usmerjanje glede na čas

Delovni čas → agent za »podporo v živo«; zunaj delovnega časa → agent za
»sprejem sporočil«. V obdelovalniku preprosto preklopite glede na
`new Date().getUTCHours()`.

---

## Naslednji koraki

<CardGroup cols={2}>
  <Card title="Referenca webhooka za dohodne klice" icon="phone" href="/sl/webhooks/call-incoming">
    Natančne sheme zahtev in odgovorov, vključno z vsakim konfiguracijskim ključem.
  </Card>
  <Card title="Preverite podpise webhookov" icon="shield-check" href="/sl/guides/verify-webhook-signatures">
    Enkrat pravilno nastavite HMAC; uporabite ga povsod.
  </Card>
  <Card title="Ustvarite integracijo orodja" icon="screwdriver-wrench" href="/sl/guides/build-tool-integration">
    Združite dinamično usmerjanje z orodji za posamezne agente.
  </Card>
  <Card title="Semantika dostave" icon="bolt" href="/sl/webhooks/overview">
    Ponovni poskusi, vrstni red, časovne omejitve.
  </Card>
</CardGroup>
