---
title: "Funkcijski alati"
description: "Omogućite svojim AI agentima funkcijske alate koji tijekom razgovora pozivaju vanjske API-je — dohvaćaju podatke o korisnicima, rezerviraju termine, ažuriraju zapise — s tipiziranim parametrima."
---

Funkcijski alati omogućuju vašim AI agentima pozivanje vanjskih API-ja tijekom telefonskih poziva. Upotrijebite ih za dohvaćanje podataka o korisnicima, provjeru dostupnosti, rezerviranje termina ili izvođenje bilo koje radnje koju vaš pozadinski sustav podržava.

## Kako funkcionira

1. Definirate alate sa shemom (koje argumente alat prihvaća)
2. Navodite konfiguraciju `endpoint` (gdje ThunderPhone poziva vaš API) — ili je izostavite kako biste pozive alata primali na webhooku svoje organizacije
3. Tijekom poziva AI odlučuje kada upotrijebiti alat na temelju razgovora
4. ThunderPhone poziva vašu krajnju točku s argumentima alata
5. Odgovor vašeg API-ja vraća se AI-ju radi nastavka razgovora

| Mogućnost | Gdje se izvršava | Postavljanje |
| --- | --- | --- |
| [Ugrađeni alati](/hr/guides/built-in-tools) | ThunderPhone | Upute u promptu; neki alati zahtijevaju i postavku agenta |
| [Povezivanja aplikacija](/hr/guides/connect-apps) | ThunderPhone i povezani pružatelj usluge | Povežite račun i priložite odobrene radnje |
| [API povezivanja](/hr/guides/api-connections) i funkcijski alati | Vaš HTTP API | Definirajte krajnju točku i shemu ili primajte pozive funkcija putem webhooka |
| [MCP poslužitelji](/hr/guides/mcp-servers) | Udaljeni MCP poslužitelj | Dodajte poslužitelj, otkrijte njegove alate i priložite ga agentu |

---

## Shema alata

Svaki alat slijedi ovu strukturu:

```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 alata

| Polje | Vrsta | Obavezno | Opis |
|-------|------|----------|-------------|
| `timeout` | broj | Ne | Maksimalno vrijeme izvršavanja u sekundama (zadano: `20`, najviše: `180`) |

### Definicija funkcije

| Polje | Vrsta | Obavezno | Opis |
|-------|------|----------|-------------|
| `name` | niz znakova | Da | Jedinstveni identifikator alata |
| `description` | niz znakova | Da | Objašnjava AI-ju kada upotrijebiti ovaj alat |
| `parameters` | objekt | Da | JSON Schema za argumente alata |

### Konfiguracija krajnje točke

| Polje | Vrsta | Obavezno | Opis |
|-------|------|----------|-------------|
| `url` | niz znakova | Da | URL krajnje točke vašeg API-ja |
| `method` | niz znakova | Ne | HTTP metoda (zadano: `POST`) |
| `headers` | objekt | Ne | Prilagođena zaglavlja koja treba uključiti |

<Note>
  Konfiguracija `endpoint` **ne** šalje se AI modelu — ThunderPhone je upotrebljava samo za izvršavanje poziva alata.
</Note>

---

## Dva načina pozivanja

Zahtjev koji vaš poslužitelj primi ovisi o tome ima li alat
`endpoint`:

| | Alat **s** `endpoint` | Alat **bez** `endpoint` |
|---|---|---|
| Odredište zahtjeva | Izravno na `endpoint.url` | [Naslijeđeni URL webhooka](/api-reference/organizations#legacy-single-url-webhook) vaše organizacije |
| Tijelo | **Samo argumenti alata** | Omotnica `telephony.tool` / `web.tool` |
| Zaglavlja | Vaša `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature` |
| Ključ za potpisivanje | Tajna webhooka organizacije | Tajna webhooka organizacije |

Oba su načina **blokirajuća** — AI usred rečenice čeka
rezultat. Zadano vremensko ograničenje je **20 s**; postavite `timeout`
alata na najvišoj razini kako biste omogućili dulje izvršavanje, do
maksimuma platforme od **180 s**. Neka obrađivači budu brzi. Kombinacija je dopuštena:
u pozivu čija organizacija ima URL webhooka alati s `endpoint` pozivaju se
izravno, a ostali se vraćaju na webhook.

## Izravni pozivi krajnjih točaka

Kada AI pozove alat koji ima `endpoint`, ThunderPhone šalje
zahtjev na Vaš URL:

### Zaglavlja zahtjeva

```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
```

Prilagođena zaglavlja iz Vašeg `endpoint.headers` uvijek se uključuju
doslovno, uz dva zaglavlja s imenskim prostorom ThunderPhonea:

- `X-ThunderPhone-Signature` — HMAC-SHA256 točnih bajtova tijela
  zahtjeva, s ključem Vaša **webhook tajna organizacije**
- `X-ThunderPhone-Call-ID` — ID trenutačnog poziva

`Content-Type: application/json` postavlja se osim ako ga Vaš `endpoint.headers`
ne nadjača — prilagođeni `Content-Type` ima prednost.

<Warning>
  Potpis koristi webhook tajnu na razini organizacije iz
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Ako Vaša organizacija nikada nije konfigurirala naslijeđeni webhook, nema
  tajne i pozivi alata sadrže **samo** `X-ThunderPhone-Call-ID` — obrađivač
  koji prekida rad ako nedostaje potpis odbio bi ih.
  Konfigurirajte naslijeđeni webhook da biste dobili tajnu ili postavite vlastitu
  dijeljenu tajnu u `endpoint.headers`.
</Warning>

### Tijelo zahtjeva

Za `POST` / `PUT` / `PATCH`, tijelo sadrži **samo** argumente alata
(bez omotača), kanonski serijalizirane (sortirani ključevi, sažeti
razdjelnici):

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

Za `GET` / `DELETE`, argumenti se šalju kao **parametri upita**
i tijelo je prazno — potpis se tada izračunava nad praznim
nizom bajtova. Pogledajte
[Provjera potpisa webhookova](/hr/guides/verify-webhook-signatures).

### Odgovor

Vratite JSON odgovor s rezultatom alata:

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

Odgovor se formatira i dostavlja AI-ju kako bi nastavio
razgovor. Odgovori koji nisu JSON omataju se kao `{"data": "<text>"}`;
vremenska ograničenja i neuspjele veze prijavljuju se AI-ju kao pogreške, pa se
agent može ispričati i nastaviti umjesto da zastane.

## Slanje u načinu webhooka

Alati **bez** `endpoint` šalju se na URL naslijeđenog webhooka Vaše organizacije
kao potpisani zahtjev `telephony.tool` (telefonski pozivi) ili `web.tool`
(web-pozivi). Za razliku od [obavijesti o reviziji](/hr/webhooks/events)
koje se dostavljaju na krajnje točke webhooka nakon izvršavanja, ovaj zahtjev **jest**
izvršavanje — Vaš HTTP odgovor rezultat je alata.

```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` sadrži `origin_domain` umjesto `from_number` /
`to_number`. Odgovorite s rezultatom alata kao JSON — isti ugovor
odgovora kao za izravne pozive krajnjih točaka. Zahtjev je potpisan webhook
tajnom organizacije nad sirovim tijelom, kao i svaki drugi webhook.

<Note>
  Pretplaćene [krajnje točke webhooka](/hr/webhooks/endpoints) dodatno
  primaju neblokirajuću `telephony.tool` / `web.tool` **obavijest
  nakon** svakog izvršavanja alata (bez obzira na put kojim je pokrenut), uključujući
  odgovor alata — korisno za revizijske tragove. Pogledajte
  [katalog događaja](/hr/webhooks/events).
</Note>

---

## Provjera potpisa

Izravni pozivi alata potpisuju se na isti način kao webhookovi:

- HMAC-SHA256 nad točnim bajtovima tijela zahtjeva (kanonski JSON —
  sortirani ključevi, bez dodatnih razmaka)
- S vašom tajnom za webhookove organizacije kao ključem
- Alati `GET` / `DELETE` potpisuju prazan niz bajtova

<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>

Potpuni primjeri — uključujući slučaj praznog tijela i napomenu o nepostojanju tajne —
nalaze se u odjeljku [Provjerite potpise webhookova](/hr/guides/verify-webhook-signatures).

---

## Primjer: potpuni tijek rezervacije

Evo skupa alata za potpuni sustav rezervacije termina:

```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" }
      }
    }
  ]
}
```

---

## Najbolje prakse

<AccordionGroup>
  <Accordion title="Napišite jasne opise">
    Polje `description` pomaže AI-ju razumjeti **kada** upotrijebiti alat. Jasno navedite što alat radi i kada ga je prikladno upotrijebiti.
  </Accordion>

  <Accordion title="Pravilno obradite pogreške">
    Vratite poruke o pogreškama koje AI može razumjeti: `{"error": "No slots available for that date"}` umjesto generičkih pogrešaka 500.
  </Accordion>

  <Accordion title="Odgovori neka budu sažeti">
    Vratite samo ono što AI-ju treba za nastavak razgovora. Veliki podaci usporavaju vrijeme odgovora.
  </Accordion>

  <Accordion title="Razumno koristite obavezna polja">
    Označite polja kao `required` samo kada je to zaista potrebno. AI će od korisnika zatražiti obavezne informacije prije pozivanja alata.
  </Accordion>
</AccordionGroup>

---

## Povezano

<CardGroup cols={2}>
  <Card title="Ugrađeni alati" icon="wrench" href="/hr/guides/built-in-tools">
    Pokrenite radnje poziva kojima upravlja platforma bez definiranja krajnje točke.
  </Card>
  <Card title="Povezivanja aplikacija" icon="plug" href="/hr/guides/connect-apps">
    Alati kojima upravlja platforma za HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets i Cal.com — krajnja točka nije potrebna.
  </Card>
  <Card title="MCP poslužitelji" icon="server" href="/hr/guides/mcp-servers">
    Priključite MCP poslužitelj i dopustite glasovnom agentu da poziva njegove alate.
  </Card>
  <Card title="API povezivanja" icon="code" href="/hr/guides/api-connections">
    Višekratne REST integracije koje možete priključiti agentima.
  </Card>
  <Card title="Provjerite potpise web-dojavnika" icon="shield-check" href="/hr/guides/verify-webhook-signatures">
    Jedan pomoćnik za provjeru web-dojavnika i poziva alata.
  </Card>
</CardGroup>
