---
title: "Funkcijska orodja"
description: "Svojim agentom UI zagotovite funkcijska orodja, ki med pogovorom kličejo zunanje API-je — pridobivajo podatke o strankah, rezervirajo termine in posodabljajo zapise — s tipiziranimi parametri."
---

Funkcijska orodja vašim glasovnim agentom omogočajo klicanje zunanjih API-jev med telefonskimi klici. Uporabite jih za iskanje podatkov o strankah, preverjanje razpoložljivosti, rezervacijo terminov ali izvajanje katerega koli dejanja, ki ga podpira vaš zaledni sistem.

## Kako deluje

1. Orodja določite s shemo (katere argumente orodje sprejema)
2. Zagotovite konfiguracijo `endpoint` (kam ThunderPhone kliče vaš API) — ali jo izpustite, da prejemate klice orodij na spletnem kavlju svoje organizacije
3. Med klicem se AI glede na pogovor odloči, kdaj uporabiti orodje
4. ThunderPhone pokliče vašo končno točko z argumenti orodja
5. Odgovor vašega API-ja se posreduje nazaj AI-ju za nadaljevanje pogovora

| Zmogljivost | Kje se izvaja | Nastavitev |
| --- | --- | --- |
| [Vgrajena orodja](/sl/guides/built-in-tools) | ThunderPhone | Navodila v pozivu; nekatera orodja potrebujejo tudi nastavitev agenta |
| [Povezave aplikacij](/sl/guides/connect-apps) | ThunderPhone in povezani ponudnik | Povežite račun in dodajte odobrena dejanja |
| [Povezave API](/sl/guides/api-connections) in funkcijska orodja | Vaš HTTP API | Določite končno točko in shemo ali prejemajte funkcijske klice prek spletnega kavlja |
| [Strežniki MCP](/sl/guides/mcp-servers) | Oddaljeni strežnik MCP | Dodajte strežnik, odkrijte njegova orodja in ga dodajte agentu |

---

## Shema orodja

Vsako orodje sledi tej strukturi:

```json
{
  "type": "function",
  "function": {
    "name": "search_appointments",
    "description": "Find available appointment slots for a given date",
    "parameters": {
      "type": "object",
      "properties": {
        "date": {
          "type": "string",
          "description": "Date in YYYY-MM-DD format"
        },
        "service": {
          "type": "string",
          "description": "Type of service (e.g., 'consultation', 'follow-up')"
        }
      },
      "required": ["date"]
    }
  },
  "endpoint": {
    "url": "https://api.example.com/appointments/search",
    "method": "POST",
    "headers": {
      "X-Api-Key": "your-api-key"
    }
  },
  "timeout": 120
}
```

### Konfiguracija orodja

| Polje | Vrsta | Obvezno | Opis |
|-------|------|----------|-------------|
| `timeout` | number | Ne | Najdaljši čas izvajanja v sekundah (privzeto: `20`, največ: `180`) |

### Definicija funkcije

| Polje | Vrsta | Obvezno | Opis |
|-------|------|----------|-------------|
| `name` | string | Da | Enolični identifikator orodja |
| `description` | string | Da | AI-ju pojasni, kdaj uporabiti to orodje |
| `parameters` | object | Da | Shema JSON za argumente orodja |

### Konfiguracija končne točke

| Polje | Vrsta | Obvezno | Opis |
|-------|------|----------|-------------|
| `url` | string | Da | URL končne točke vašega API-ja |
| `method` | string | Ne | Metoda HTTP (privzeto: `POST`) |
| `headers` | object | Ne | Glave po meri, ki jih želite vključiti |

<Note>
  Konfiguracija `endpoint` se modelu AI **ne** pošlje — ThunderPhone jo uporablja samo za izvedbo klica orodja.
</Note>

---

## Dve poti klicanja

Katero zahtevo prejme vaš strežnik, je odvisno od tega, ali ima orodje
`endpoint`:

| | Orodje **z** `endpoint` | Orodje **brez** `endpoint` |
|---|---|---|
| Kam se pošlje zahteva | Neposredno na `endpoint.url` | Na [podedovani URL spletnega kavlja](/api-reference/organizations#legacy-single-url-webhook) vaše organizacije |
| Telo | **Sami argumenti orodja** | Ovojnica `telephony.tool` / `web.tool` |
| Glave | Vaše `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature` |
| Ključ za podpisovanje | Skrivnost spletnega kavlja organizacije | Skrivnost spletnega kavlja organizacije |

Obe poti sta **blokirni** — AI sredi stavka čaka na
rezultat. Privzeta časovna omejitev je **20 s**; nastavite `timeout`
na najvišji ravni orodja, da omogočite daljše izvajanje, do največje
omejitve platforme **180 s**. Obravnavalnike ohranite hitre. Kombinacija je povsem ustrezna:
pri klicu, katerega organizacija ima URL spletnega kavlja, se orodja z `endpoint`
pokličejo neposredno, preostala pa uporabijo spletni kavelj.

## Neposredni klici končnih točk

Ko AI pokliče orodje, ki ima `endpoint`, ThunderPhone pošlje
zahtevo na vaš URL:

### Glave zahtev

```http
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key
```

Glave po meri iz vašega `endpoint.headers` so vedno vključene
dobesedno, poleg dveh glav v imenskem prostoru ThunderPhone:

- `X-ThunderPhone-Signature` — HMAC-SHA256 natančnih bajtov telesa
  zahteve, pri čemer je ključ vaš **skrivni ključ webhooka organizacije**
- `X-ThunderPhone-Call-ID` — ID trenutnega klica

`Content-Type: application/json` je nastavljen, razen če ga vaš `endpoint.headers`
prepiše — `Content-Type` po meri ima prednost.

<Warning>
  Podpis uporablja skrivni ključ webhooka na ravni organizacije iz
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Če vaša organizacija nikoli ni konfigurirala starejšega webhooka, skrivni
  ključ ne obstaja in klici orodij vsebujejo **samo** `X-ThunderPhone-Call-ID` —
  obdelovalnik, ki ob manjkajočem podpisu neuspešno zaključi izvajanje, bi jih zavrnil.
  Za pridobitev skrivnega ključa konfigurirajte starejši webhook ali v
  `endpoint.headers` dodajte svoj skupni skrivni ključ.
</Warning>

### Telo zahteve

Za `POST` / `PUT` / `PATCH` telo vsebuje **samo** argumente orodja
(brez ovoja), kanonično serializirane (razvrščeni ključi, strnjena
ločila):

```json
{"date":"2025-01-02","service":"consultation"}
```

Za `GET` / `DELETE` so argumenti poslani kot **parametri poizvedbe**
in telo je prazno — podpis se nato izračuna nad praznim bajtnim
nizom. Oglejte si
[Preverjanje podpisov webhookov](/sl/guides/verify-webhook-signatures).

### Odgovor

Vrnite odgovor JSON z rezultatom orodja:

```json
{
  "available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
  "timezone": "America/Los_Angeles"
}
```

Odgovor je oblikovan in posredovan AI, da nadaljuje
pogovor. Odgovori, ki niso JSON, so oviti kot `{"data": "<text>"}`;
prekinitve zaradi časovne omejitve in povezave so AI sporočene kot napake, zato
se lahko agent opraviči in nadaljuje, namesto da obstane.

## Posredovanje v načinu webhook

Orodja **brez** `endpoint` so posredovana na URL starejšega webhooka vaše
organizacije kot podpisana zahteva `telephony.tool` (telefonski klici) ali `web.tool`
(spletni klici). Za razliko od [obvestil za revizijo](/sl/webhooks/events),
dostavljenih na končne točke webhookov po izvedbi, ta zahteva **je**
izvedba — vaš odgovor HTTP je rezultat orodja.

```json
{
  "type": "telephony.tool",
  "data": {
    "call_id": 987654321,
    "tool_name": "search_appointments",
    "arguments": { "date": "2026-04-21" },
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  }
}
```

`web.tool` namesto `from_number` /
`to_number` vsebuje `origin_domain`. Na rezultat orodja odgovorite kot JSON — velja ista
pogodba za odgovor kot pri neposrednih klicih končnih točk. Zahteva je s skrivnim ključem
webhooka organizacije podpisana nad neobdelanim telesom, kot vsak drug webhook.

<Note>
  Naročene [končne točke webhookov](/sl/webhooks/endpoints) dodatno
  prejmejo neblokirajoče `telephony.tool` / `web.tool` **obvestilo po**
  vsaki izvedbi orodja (ne glede na pot, ki ga je izvedla), vključno z
  odgovorom orodja — uporabno za revizijske sledi. Oglejte si
  [katalog dogodkov](/sl/webhooks/events).
</Note>

---

## Preverjanje podpisa

Neposredni klici orodij so podpisani enako kot spletni kljuki:

- HMAC-SHA256 nad natančnimi bajti telesa zahteve (kanonični JSON —
  razvrščeni ključi, brez dodatnih presledkov)
- S ključem, ki je skrivnost spletne kljuke vaše organizacije
- Orodja `GET` / `DELETE` podpišejo prazen niz bajtov

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

def verify_tool_call(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

@app.post("/appointments/search")
async def search_appointments(request: Request):
    body = await request.body()
    signature = request.headers.get("X-ThunderPhone-Signature", "")

    if not verify_tool_call(body, signature, WEBHOOK_SECRET):
        raise HTTPException(status_code=401)

    data = json.loads(body)
    date = data["date"]

    # Look up availability
    slots = await get_available_slots(date)

    return {"available_slots": slots}
```

```javascript Node.js
app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-thunderphone-signature'] || '';
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');

  if (!signature ||
      signature.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
    return res.status(401).send('Invalid signature');
  }

  const { date, service } = JSON.parse(req.body);

  // Look up availability
  const slots = getAvailableSlots(date, service);

  res.json({ available_slots: slots });
});
```
</CodeGroup>

Celotni recepti — vključno s primerom praznega telesa in opozorilom glede odsotnosti skrivnosti —
so v razdelku [Preverjanje podpisov spletnih kljuk](/sl/guides/verify-webhook-signatures).

---

## Primer: celoten potek rezervacije

Tukaj je nabor orodij za celoten sistem rezervacije terminov:

```json
{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "search_appointments",
        "description": "Find available appointment slots",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "service": { "type": "string" }
          },
          "required": ["date"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/search",
        "method": "POST",
        "headers": { "X-Api-Key": "key" }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "book_appointment",
        "description": "Book an appointment at a specific time",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "time": { "type": "string", "description": "HH:MM format" },
            "customer_name": { "type": "string" },
            "customer_phone": { "type": "string" }
          },
          "required": ["date", "time", "customer_name"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/book",
        "method": "POST",
        "headers": { "X-Api-Key": "key" }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "cancel_appointment",
        "description": "Cancel an existing appointment",
        "parameters": {
          "type": "object",
          "properties": {
            "confirmation_number": { "type": "string" }
          },
          "required": ["confirmation_number"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/cancel",
        "method": "POST",
        "headers": { "X-Api-Key": "key" }
      }
    }
  ]
}
```

---

## Najboljše prakse

<AccordionGroup>
  <Accordion title="Napišite jasne opise">
    Polje `description` pomaga UI razumeti, **kdaj** uporabiti orodje. Natančno opišite, kaj počne in kdaj ga je primerno uporabiti.
  </Accordion>

  <Accordion title="Ustrezno obravnavajte napake">
    Vrnite sporočila o napakah, ki jih UI razume: `{"error": "No slots available for that date"}` namesto splošnih napak 500.
  </Accordion>

  <Accordion title="Odgovori naj bodo jedrnati">
    Vrnite samo tisto, kar UI potrebuje za nadaljevanje pogovora. Velika bremena upočasnijo odzivni čas.
  </Accordion>

  <Accordion title="Polja, ki so obvezna, uporabljajte premišljeno">
    Polja označite kot `required` le, kadar je to res potrebno. UI bo pred klicem orodja uporabnika vprašala za zahtevane informacije.
  </Accordion>
</AccordionGroup>

---

## Sorodno

<CardGroup cols={2}>
  <Card title="Vgrajena orodja" icon="wrench" href="/sl/guides/built-in-tools">
    Sprožite dejanja klicev, ki jih upravlja platforma, brez določanja končne točke.
  </Card>
  <Card title="Povezave z aplikacijami" icon="plug" href="/sl/guides/connect-apps">
    Orodja, ki jih upravlja platforma, za HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets in Cal.com — končna točka ni potrebna.
  </Card>
  <Card title="Strežniki MCP" icon="server" href="/sl/guides/mcp-servers">
    Pripnite strežnik MCP in agentu omogočite klic njegovih orodij.
  </Card>
  <Card title="Povezave API" icon="code" href="/sl/guides/api-connections">
    Integracije REST za večkratno uporabo, ki jih lahko pripnete agentom.
  </Card>
  <Card title="Preverite podpise webhookov" icon="shield-check" href="/sl/guides/verify-webhook-signatures">
    En pomočnik za preverjanje webhookov in klicev orodij.
  </Card>
</CardGroup>
