---
title: "Funktiotyökalut"
description: "Anna AI-agenteillesi funktiotyökaluja, jotka kutsuvat ulkoisia API-rajapintoja kesken keskustelun — hakevat asiakastietoja, varaavat tapaamisia ja päivittävät tietueita — tyyppimääritetyillä parametreilla."
---

Funktiotyökalujen avulla AI-agenttisi voivat kutsua ulkoisia API-rajapintoja puheluiden aikana. Käytä niitä asiakastietojen hakemiseen, saatavuuden tarkistamiseen, tapaamisten varaamiseen tai mihin tahansa toimintoon, jota taustajärjestelmäsi tukee.

## Näin se toimii

1. Määrität työkalut skeemalla (mitkä argumentit työkalu hyväksyy)
2. Määrität `endpoint`-asetuksen (mihin ThunderPhone kutsuu API-rajapintaasi) — tai jätät sen pois, jolloin saat työkalukutsut organisaatiosi webhookiin
3. Puhelun aikana tekoäly päättää keskustelun perusteella, milloin työkalua käytetään
4. ThunderPhone kutsuu päätepistettäsi työkalun argumenteilla
5. API-vastauksesi välitetään takaisin tekoälylle keskustelun jatkamiseksi

| Ominaisuus | Missä se suoritetaan | Määritys |
| --- | --- | --- |
| [Sisäänrakennetut työkalut](/fi/guides/built-in-tools) | ThunderPhone | Kehoteohjeet; jotkin työkalut tarvitsevat myös agenttiasetuksen |
| [Sovellusyhteydet](/fi/guides/connect-apps) | ThunderPhone ja yhdistetty palveluntarjoaja | Yhdistä tili ja liitä hyväksytyt toiminnot |
| [API-yhteydet](/fi/guides/api-connections) ja funktiotyökalut | HTTP API-rajapintasi | Määritä päätepiste ja skeema tai vastaanota funktiokutsut webhookin kautta |
| [MCP-palvelimet](/fi/guides/mcp-servers) | Etäinen MCP-palvelin | Lisää palvelin, hae sen työkalut ja liitä se agenttiin |

---

## Työkalun skeema

Jokainen työkalu noudattaa tätä rakennetta:

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

### Työkalun määritys

| Kenttä | Tyyppi | Pakollinen | Kuvaus |
|-------|------|----------|-------------|
| `timeout` | numero | Ei | Enimmäissuoritusaika sekunteina (oletus: `20`, enintään: `180`) |

### Funktiomääritelmä

| Kenttä | Tyyppi | Pakollinen | Kuvaus |
|-------|------|----------|-------------|
| `name` | merkkijono | Kyllä | Työkalun yksilöllinen tunniste |
| `description` | merkkijono | Kyllä | Kertoo tekoälylle, milloin tätä työkalua käytetään |
| `parameters` | objekti | Kyllä | JSON-skeema työkalun argumenteille |

### Päätepisteen määritys

| Kenttä | Tyyppi | Pakollinen | Kuvaus |
|-------|------|----------|-------------|
| `url` | merkkijono | Kyllä | API-rajapintasi päätepisteen URL-osoite |
| `method` | merkkijono | Ei | HTTP-metodi (oletus: `POST`) |
| `headers` | objekti | Ei | Mukaan sisällytettävät mukautetut otsakkeet |

<Note>
  `endpoint`-asetusta **ei** lähetetä tekoälymallille — ThunderPhone käyttää sitä vain työkalukutsun suorittamiseen.
</Note>

---

## Kaksi kutsutapaa

Palvelimesi vastaanottama pyyntö riippuu siitä, onko työkalulla
`endpoint`:

| | Työkalu, jossa on `endpoint` | Työkalu, jossa ei ole `endpoint` |
|---|---|---|
| Mihin pyyntö lähetetään | Suoraan osoitteeseen `endpoint.url` | Organisaatiosi [vanhaan webhook-URL-osoitteeseen](/api-reference/organizations#legacy-single-url-webhook) |
| Runko | Valittu pyyntömuoto (oletuksena pelkät argumentit) | `telephony.tool` / `web.tool` -kirjekuori |
| Otsakkeet | Sinun `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` |
| Allekirjoitusavain | Organisaation webhook-salaisuus | Organisaation webhook-salaisuus |

Molemmat tavat ovat **synkronisia** — tekoäly odottaa tulosta kesken
lauseen. Oletusaikakatkaisu on **20 s**; määritä työkalun ylimmän tason
`timeout`, jos tarvitset pidemmän suoritusajan, enintään alustan **180 s**
-rajaan asti. Pidä käsittelijät nopeina. Voit käyttää molempia:
puhelussa, jonka organisaatiolla on webhook-URL-osoite, työkalut, joilla on `endpoint`,
kutsutaan suoraan ja muut käyttävät webhookia.

## Suorat päätepistekutsut

Kun tekoäly kutsuu työkalua, jolla on `endpoint`, ThunderPhone lähettää
pyynnön URL-osoitteeseesi:

### Pyynnön otsakkeet

```http
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature-V2: t=1767225600,v1=5f2c...
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-key
```

Omat `endpoint.headers`-otsakkeesi sisällytetään aina sellaisinaan
sekä seuraavat ThunderPhone-nimiavaruuden otsakkeet:

- `X-ThunderPhone-Signature-V2` — aikaleimattu HMAC-SHA256 metodista,
  polusta, kyselystä ja rungosta, avaimena organisaatiosi **webhook-salaisuus**.
  Vahvista tämä ja hylkää yli 5 minuuttia vanhat pyynnöt; katso
  [Vahvista webhook-allekirjoitukset](/fi/guides/verify-webhook-signatures)
- `X-ThunderPhone-Signature` — vanha HMAC-SHA256 pyynnön rungon tarkoista
  tavuista samalla avaimella; lähetetään edelleen olemassa olevia vahvistajia varten
- `X-ThunderPhone-Call-ID` — Nykyisen puhelun tunniste

`Content-Type: application/json` asetetaan, ellei `endpoint.headers`
ohita sitä — mukautettu `Content-Type` on ensisijainen.

<Warning>
  Allekirjoituksen avaimena käytetään organisaatiotason webhook-salaisuutta,
  joka haetaan osoitteesta
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Jos organisaatiosi ei ole koskaan määrittänyt vanhaa webhookia, salaista
  avainta ei ole, ja työkalukutsut sisältävät **vain**
  `X-ThunderPhone-Call-ID`-otsakkeen — käsittelijä, joka epäonnistuu
  puuttuvan allekirjoituksen vuoksi, hylkäisi ne.
  Määritä joko vanha webhook saadaksesi salaisen avaimen tai lisää oma
  jaettu salainen avain kohtaan `endpoint.headers`.
</Warning>

### Pyyntömuoto

Jokaisella API-yhteydellä on `request_format`-asetus. Valitse `vapi` tai
`retell`, kun tuodun työkalun tulee edelleen kutsua kyseiselle alustalle
rakennettua päätepistettä. Uusien ja olemassa olevien yhteyksien oletusarvo on `standard`.

Kohteille `POST` / `PUT` / `PATCH` ThunderPhone sarjallistaa valitun
verhon kanonisesti (avaimet lajiteltuina, tiiviit erottimet). Molemmat allekirjoitukset
kattavat nämä täsmälliset tavut.

#### Standard

`standard` lähettää vain työkalun argumentit ilman käärettä. Tämä on
oletusasetus, ja se säilyttää ThunderPhonen alkuperäisen pyynnön rungon tavusta tavuun:

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

#### Vapi

`vapi` lähettää Vapin [palvelinviestin `tool-calls`](https://docs.vapi.ai/tools/custom-tools)
Vapin dokumentoimassa muodossa. `call.id` on ThunderPhone-puhelun tunniste. Työkalukutsun
`id` on yksilöllinen kutsulle, ja sitä käytetään uudelleen päätepisteen tuloksen
yhdistämiseen. Puhelu näkyy sekä kohteessa `toolCallList` että
`toolWithToolCallList`, ja `function.arguments` on JSON-objekti:

```json
{
  "message": {
    "type": "tool-calls",
    "timestamp": 1725000000123,
    "call": { "id": "987654321" },
    "toolCallList": [
      {
        "id": "call_00112233445566778899aabbccddeeff",
        "type": "function",
        "function": {
          "name": "search_appointments",
          "arguments": { "date": "2025-01-02", "service": "consultation" }
        }
      }
    ],
    "toolWithToolCallList": [
      {
        "type": "function",
        "function": { "name": "search_appointments" },
        "toolCall": {
          "id": "call_00112233445566778899aabbccddeeff",
          "type": "function",
          "function": {
            "name": "search_appointments",
            "arguments": { "date": "2025-01-02", "service": "consultation" }
          }
        }
      }
    ]
  }
}
```

Vapi-kohtaisia kenttiä, kuten `assistant`, `artifact` ja koko `call`-objektia,
ei lähetetä.

Palauta Vapin vastausverho vastaavalla työkalukutsun tunnisteella:

```json
{
  "results": [
    {
      "toolCallId": "call_00112233445566778899aabbccddeeff",
      "result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
    }
  ]
}
```

ThunderPhone antaa tekoälylle käärimättömän `result`-merkkijonon. Se hyväksyy myös
JSON-arvon yhteensopivuuden vuoksi sellaisten päätepisteiden kanssa, jotka jo palauttavat
sellaisen. `error`-kenttä `result`-kentän tilalla palautetaan tekoälylle työkalun virheenä.
Jos päätepiste palauttaa virheellisen muotoisen tai täsmäämättömän Vapi-verhon, ThunderPhone kirjaa
varoituksen ja palaa vakiovastauksen jäsennykseen puhelun epäonnistamisen sijaan.

#### Retell

`retell` lähettää [Retell-mukautetulle
funktiolle](https://docs.retellai.com/build/single-multi-prompt/custom-function) dokumentoidun pyynnön:

```json
{
  "name": "search_appointments",
  "call": { "call_id": "987654321" },
  "args": { "date": "2025-01-02", "service": "consultation" }
}
```

`call`-objekti sisältää vain kentän `call_id`. ThunderPhone ei sisällytä
Retell-kohtaisia kenttiä, joita se ei voi rehellisesti toimittaa lähetysvaiheessa, kuten
`agent_id`, `transcript`, `transcript_object`, `metadata` tai dynaamisia
muuttujia. Retell hyväksyy minkä tahansa vastausrungon; ThunderPhone välittää sen
vakiovastauskäsittelyllä.

Kohteille `GET` / `DELETE` argumentit lähetetään **kyselyparametreina**,
ja runko on tyhjä `request_format`-asetuksesta riippumatta. V2-allekirjoitus
kattaa lähetetyn kyselymerkkijonon; vanha allekirjoitus lasketaan
tyhjästä tavumerkkijonosta. Katso
[Webhook-allekirjoitusten vahvistaminen](/fi/guides/verify-webhook-signatures).

### Vastaus

Palauta työkalun tulos JSON-vastauksena:

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

Vastaus muotoillaan ja toimitetaan tekoälylle keskustelun jatkamiseksi.
Muut kuin JSON-vastaukset kääritään muotoon `{"data": "<text>"}`;
aikakatkaisuista ja yhteysvirheistä ilmoitetaan tekoälylle virheinä,
jotta agentti voi pyytää anteeksi ja jatkaa sen sijaan, että se jäisi
odottamaan.

## Välitys webhook-tilassa

Työkalut, joilla **ei ole** `endpoint`-määritystä, välitetään organisaatiosi
vanhaan webhook-URL-osoitteeseen allekirjoitettuna `telephony.tool`-
(puhelut) tai `web.tool`-pyyntönä (verkkopuhelut). Toisin kuin
[audit-ilmoitukset](/fi/webhooks/events), jotka toimitetaan webhook-päätepisteisiin
suorituksen jälkeen, tämä pyyntö **on** itse suoritus — HTTP-vastauksesi
on työkalun tulos.

```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` sisältää `origin_domain`-kentän `from_number`- /
`to_number`-kenttien sijaan. Vastaa työkalun tuloksella JSON-muodossa — sama
vastaussopimus kuin suorissa päätepistekutsuissa. Pyyntö on allekirjoitettu organisaation
webhook-salaisuudella ja sisältää molemmat allekirjoitusotsakkeet, kuten kaikki muutkin webhookit.

<Note>
  Tilatut [webhook-päätepisteet](/fi/webhooks/endpoints) vastaanottavat lisäksi
  ei-estävän `telephony.tool` / `web.tool` **ilmoituksen jokaisen
  työkalusuorituksen jälkeen** (riippumatta siitä, mitä reittiä se suoritettiin),
  mukaan lukien työkalun vastauksen — hyödyllistä auditointijälkiä varten.
  Katso [tapahtumaluettelo](/fi/webhooks/events).
</Note>

---

## Allekirjoituksen vahvistus

Suorat työkalukutsut allekirjoitetaan samalla tavalla kuin webhookit käyttäen
organisaatiosi webhook-salaisuutta:

- `X-ThunderPhone-Signature-V2` allekirjoittaa aikaleiman, metodin, polun ja
  kyselyparametrit lähetetyssä muodossa sekä tarkat pyynnön rungon tavut. Hylkää pyynnöt, joiden
  aikaleima poikkeaa kellostasi yli 5 minuuttia.
- `X-ThunderPhone-Signature` (vanha versio) allekirjoittaa vain pyynnön rungon tavut tai
  tyhjän tavujonon pyynnöille `GET` / `DELETE`. Se lähetetään edelleen muuttumattomana.

SDK-aputoiminnot tarkistavat V2-otsakkeen, mukaan lukien 5 minuutin aikarajan:

<CodeGroup>
```python Python
import json

from fastapi import FastAPI, HTTPException, Request
from thunderphone import verify_signature

app = FastAPI()

@app.post("/appointments/search")
async def search_appointments(request: Request):
    body = await request.body()
    query = request.scope.get("query_string", b"").decode("latin-1")
    path = request.url.path + (f"?{query}" if query else "")

    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=WEBHOOK_SECRET,
        method=request.method,
        path=path,
        body=body,
    ):
        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
import express from "express";
import { verifySignature } from "@thunderphone/sdk";

app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
  const ok = verifySignature({
    header: req.header('X-ThunderPhone-Signature-V2'),
    secret: WEBHOOK_SECRET,
    method: req.method,
    path: req.originalUrl,
    body: req.body,
  });
  if (!ok) 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>

Täydelliset ohjeet — allekirjoitettava merkkijono, käytännön esimerkki, koodi ilman
SDK:ta, `GET` / `DELETE` -tapaus ja huomautus tilanteesta, jossa salaista avainta ei ole — ovat kohdassa [Webhook-allekirjoitusten vahvistaminen](/fi/guides/verify-webhook-signatures).

---

## Esimerkki: täydellinen varausprosessi

Tässä on työkalut täydelliseen ajanvarausjärjestelmään:

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

---

## Parhaat käytännöt

<AccordionGroup>
  <Accordion title="Kirjoita selkeät kuvaukset">
    Kenttä `description` auttaa tekoälyä ymmärtämään, **milloin** työkalua käytetään. Kerro tarkasti, mitä se tekee ja milloin sen käyttö on tarkoituksenmukaista.
  </Accordion>

  <Accordion title="Käsittele virheet hallitusti">
    Palauta virheilmoituksia, jotka tekoäly ymmärtää: `{"error": "No slots available for that date"}` yleisten 500-virheiden sijaan.
  </Accordion>

  <Accordion title="Pidä vastaukset ytimekkäinä">
    Palauta vain se, mitä tekoäly tarvitsee keskustelun jatkamiseksi. Suuret hyötykuormat hidastavat vastausaikoja.
  </Accordion>

  <Accordion title="Käytä pakollisia kenttiä harkiten">
    Merkitse kentät `required`-kentiksi vain, kun se on todella tarpeen. Tekoäly pyytää käyttäjältä pakolliset tiedot ennen työkalun kutsumista.
  </Accordion>
</AccordionGroup>

---

## Aiheeseen liittyvää

<CardGroup cols={2}>
  <Card title="Sisäänrakennetut työkalut" icon="wrench" href="/fi/guides/built-in-tools">
    Käynnistä alustan hallinnoimia puhelutoimintoja määrittämättä päätepistettä.
  </Card>
  <Card title="Sovellusyhteydet" icon="plug" href="/fi/guides/connect-apps">
    Alustan hallinnoimat työkalut HubSpotille, Salesforcelle, Slackille, Google
    Calendarille, Google Sheetsille ja Cal.comille — päätepistettä ei tarvita.
  </Card>
  <Card title="MCP-palvelimet" icon="server" href="/fi/guides/mcp-servers">
    Liitä MCP-palvelin ja anna agentin kutsua sen työkaluja.
  </Card>
  <Card title="API-yhteydet" icon="code" href="/fi/guides/api-connections">
    Uudelleenkäytettävät REST-integraatiot, jotka voit liittää agentteihin.
  </Card>
  <Card title="Vahvista webhook-allekirjoitukset" icon="shield-check" href="/fi/guides/verify-webhook-signatures">
    Yksi varmennusapuri webhookeille ja työkalukutsuille.
  </Card>
</CardGroup>
