---
title: "Rakenna työkalintegraatio (API)"
description: "Anna agenttisi kutsua API-rajapintojasi kesken keskustelun – hae tietoa tietokannasta, luo tukipyyntö tai etsi tilaus."
---

**työkalintegraatio** on uudelleenkäytettävä HTTP-päätepiste, jonka agentti voi
kutsua puhelun aikana. Annat ThunderPhonelle työkalun JSON-skeemakuvauksen
sekä päätepisteen URL-osoitteen; agentti päättää keskustelun perusteella,
milloin sitä kutsutaan, ja ThunderPhone tekee lähtevän HTTP-pyynnön
palvelimiltaan ja palauttaa vastauksen agentille.

<Note>
  Hallintapaneeli kattaa useimmat työkalutarpeet ilman tätä APIa: **Yhteydet
  → Sovellukset** yhdistää Slackin, HubSpotin, Salesforcen, Google Calendarin,
  Google Sheetsin ja Cal.comin muutamalla OAuth-klikkauksella; **Yhteydet →
  API:t** muuttaa minkä tahansa HTTP-API:n agenttitoiminnoksi (liitä cURL-komento,
  niin AI-avustaja laatii työkalun, jossa on sisäänrakennettu Pyynnön testaus);
  ja **Yhteydet → MCP** lisää MCP-palvelimia. Katso
  [Yhteydet](/fi/guides/concepts). Tämä opas käsittelee API:t-näkymän
  taustalla olevaa raakaa APIa.
</Note>

Tässä oppaassa rakennetaan säähaun työkalu alusta loppuun.

## Työkalun rakenne

Kaksi osaa:

1. **Skeema** — OpenAI-tyylinen funktiomäärittely
   (`{type: "function", function: {name, description, parameters}}`),
   joka kertoo LLM:lle, mitä työkalu tekee ja mitä argumentteja se vastaanottaa.
2. **Päätepiste** — URL-osoite, johon ThunderPhonen palvelimet soittavat, kun
   LLM päättää käyttää työkalua. Pyyntö on JSON POST, jonka runkona ovat
   LLM:n valitsemat argumentit.

## 1. Valitse editori

<CardGroup cols={2}>
  <Card title="Hallintapaneeli" icon="window-maximize">
    Avaa **Yhteydet → API:t**, luo tai muokkaa API-yhteyttä,
    vaihda parametrieditorin tilaksi **JSON** ja lisää määrittely sinne.
  </Card>
  <Card title="Integraatioiden API" icon="plug">
    Luo määrittely komennolla `POST /v1/integrations` tai päivitä se komennolla
    `PATCH /v1/integrations/{id}`.
  </Card>
</CardGroup>

Molemmilla tavoilla luodaan tallennettu integraatio. Liitä integraatio
agenttiin tallennuksen jälkeen. Agenttien APIssa ei ole kirjoitettavaa
sisäistä `tools`-kenttää. Tässä oppaassa käytetään integraatioiden API-polkuja.

## 2. Luo integraatio

```bash
curl -X POST https://api.thunderphone.com/v1/integrations \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Weather API",
    "spec": {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Return the current weather for a zip code.",
        "parameters": {
          "type": "object",
          "properties": {
            "zip": { "type": "string", "description": "5-digit US ZIP code" }
          },
          "required": ["zip"]
        }
      }
    },
    "endpoint_url":    "https://api.example.com/weather",
    "endpoint_method": "GET",
    "headers": [
      { "key": "X-Api-Key", "value": "your-provider-key" }
    ]
  }'
```

Tallenna palautettu `id` (UUID). Otsakearvot ovat vain kirjoitettavia: vastaukset
luettelevat vain otsakkeiden nimet, ja myöhempi `PATCH` voi lähettää otsakkeen ilman
`value`-arvoa säilyttääkseen tallennetun arvon.

<Tip>
  Panosta kunnolla työkalun ja jokaisen parametrin `description`-kuvauksiin. LLM käyttää
  näitä merkkijonoja ajonaikana päättääkseen, kutsutaanko työkalua ja miten sitä
  kutsutaan. Epämääräiset kuvaukset → epämääräiset työkalukutsut.
</Tip>

### Määritä osoiteparametreille `format: "email"`

Sähköpostiosoitteen vastaanottavan parametrin tulee ilmoittaa se
skeemassaan:

```json
"email": { "type": "string", "format": "email", "description": "The caller's email address" }
```

`format` on enemmän kuin vihje. Ratkaistulle sähköpostiskeemalle ThunderPhone
poistaa arvon alusta ja lopusta välilyönnit, muuntaa verkkotunnuksen pieniksi kirjaimiksi,
muuttaa itsenäiset englanninkieliset sanat `at`, `dot`, `underscore`,
`dash` ja `hyphen` merkeikseen sekä poistaa välilyönnit suoraan merkkien
`@`, `.`, `_` ja `-` ympäriltä ennen päätepisteesi kutsumista. Sanoilla on sama merkitys
riippumatta siitä, sisältääkö transkriptio jo kirjaimellisen `@`-merkin:
`"john dot smith at gmail dot com"` muuttuu muotoon
`john.smith@gmail.com`.

Muut sisäiset välilyönnit hylätään sen sijaan, että ne yhdistettäisiin hiljaisesti.
Puhutut erotinsanat ovat vain englanninkielisiä; muunkieliset tai tunnistamattomat
välilyönneillä erotetut muodot hylätään. Kelvolliset kansainvälistetyt verkkotunnukset ja
SMTPUTF8-paikallisosat hyväksytään. Punycode-syöte säilyy punycodena ja Unicode-verkkotunnussyöte
säilyy Unicodena jäsentimen normalisoinnin jälkeen, joten API:si vastaanottaa soittajan
antaman tavanomaisen esitystavan. Jos lopullinen arvo on virheellinen, työkalua **ei kutsuta**.
Agentti vastaanottaa virheen `invalid_email_argument`, joka ohjaa sitä
vahvistamaan kirjoitusasun soittajan kanssa ja lähettämään kirjaimellisen osoitteen uudelleen.

Pois jätettyä valinnaista sähköpostiosoitetta ei muuteta. Myös `null`, tyhjä merkkijono tai
pelkistä välilyönneistä koostuva merkkijono jätetään muuttamatta, kun ominaisuus on valinnainen
tai voi olla null; samat arvot hylätään pakolliselta sähköpostiosoitteelta, joka ei voi olla null.

Paikalliset skeemaviittaukset, kuten `#/$defs/email` ja
`#/definitions/email`, sekä `anyOf`, `oneOf` ja `allOf` tarkastetaan
sykli- ja syvyysrajoituksin. Ei-paikallinen tai ratkaisematon `$ref` on tunnettu
valvonnan rajoitus ja välitetään muuttamattomana, samoin kuin kutsu, jonka
työkalutilannekuvassa ei ole käyttökelpoista skeemaa. Pidä sähköpostiskeemat paikallisina, kun
tarvitset tarkistuksen käyttöön.

Parametrit, joilla ei ole pakotettua sähköpostimuotoa, välitetään täsmälleen
sellaisina kuin malli ne tuotti.

Tuetut muodot ovat `date-time`, `time`, `date`, `duration`,
`email`, `hostname`, `ipv4`, `ipv6` ja `uuid`; vain `email`
normalisoidaan ja pakotetaan tällä hetkellä.

## 3. Testaa päätepiste hiekkalaatikossa

Ennen kuin liität integraation agenttiin, lähetä allekirjoitettu pyyntö
ThunderPhonen palvelimilta yhteyden varmistamiseksi:

```bash
curl -X POST https://api.thunderphone.com/v1/integrations/test-request \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url":    "https://api.example.com/weather?zip=94110",
    "method": "GET",
    "headers": { "X-Api-Key": "your-provider-key" }
  }'
```

```json Response
{
  "ok": true,
  "status": 200,
  "elapsed_ms": 187,
  "response_headers": { "content-type": "application/json" },
  "response_preview": "{\"temperature_f\": 64, ...}"
}
```

Tämä testi vahvistaa myös ThunderPhonen SSRF-suojauksia — localhostiin tai yksityisiin IP-alueisiin kohdistuvat pyynnöt palauttavat virheen `400 code=url_not_allowed`.

## 4. Liitä integraatio agenttiin

Liitä `integration_ids`-kentän avulla, kun luot tai päivität agentin:

```bash
curl -X PATCH https://api.thunderphone.com/v1/agents/12 \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_ids": ["f9b5a1a4-..."]
  }'
```

Voit liittää yhteen agenttiin useita integraatioita. Agentin kehotteessa voi
viitata niihin nimellä — "käytä `get_weather`-toimintoa, kun soittaja kysyy
sääolosuhteista" — tai agentti voi tunnistaa ne epäsuorasti
skeemakuvausten perusteella.

## 5. Toteuta päätepiste

Kun agentti kutsuu työkalua, ThunderPhone lähettää allekirjoitetun POST-pyynnön
osoitteeseen `endpoint_url`:

```
POST /weather HTTP/1.1
Host: api.example.com
X-Api-Key: your-provider-key
X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<HMAC-SHA256 hex>
X-ThunderPhone-Signature: <HMAC-SHA256 hex>
X-ThunderPhone-Call-ID: 987654321
Content-Type: application/json

{"zip": "94110"}
```

Palvelimesi vastaa JSONilla, joka välitetään takaisin LLM:lle:

```json
{"temperature_f": 64, "condition": "Partly cloudy", "wind_mph": 8}
```

LLM käsittelee vastauksen ja kertoo soittajalle selkokielisen yhteenvedon.

<Warning>
  Allekirjoitus lasketaan pyynnön raakasisällöstä käyttämällä samaa
  `secret`-arvoa kuin webhook-päätepisteessäsi. **Vahvista se** —
  työkalupäätepisteet ovat internetiin avoimia, ja niihin kohdistuu samat
  väärentämiseen liittyvät riskit kuin webhookeihin. Katso
  [Webhook-allekirjoitusten vahvistaminen](/fi/guides/verify-webhook-signatures).
</Warning>

## 6. Testaa kokonaisuus

Käynnistä agenttia vastaan [mikrofonisessio](/api-reference/mic-sessions)
ja kysy kysymys, jonka työkalusi käsittelee ("Mikä sää on alueella
94110?"). Puhelun litterointi näyttää koko kierroksen:

```json
{
  "call_id": 987654321,
  "transcripts": [
    { "role": "user",
      "content": "What's the weather in 94110?" },
    { "role": "tool_call",
      "content": "{\"tool_call\": \"get_weather\", \"arguments\": {\"zip\": \"94110\"}}" },
    { "role": "tool_response",
      "content": "{\"tool_name\": \"get_weather\", \"response\": {\"temperature_f\": 64, \"condition\": \"Partly cloudy\"}}" },
    { "role": "agent",
      "content": "It's 64 degrees and partly cloudy." }
  ]
}
```

Voit hakea tämän osoitteesta
[`GET /v1/calls/{call_id}/transcript`](/api-reference/calls#get-transcript);
raaka tapahtumavirta (jossa on kunkin merkinnän ajoitus- ja äänisiirtymät)
on osoitteessa
[`GET /v1/calls/{call_id}/history`](/api-reference/calls#get-history).

Puheluluetteloissa ja analytiikkanäkymissä ThunderPhone raportoi nyt testipuhelut erillään todellisesta liikenteestä. Browser Talk -testit ja simulaatiot voivat käyttää uudelleen oikeaa puhelinnumeroa ja näyttää saapuvilta puheluilta, mutta niitä ei lasketa mukaan tuotannon puhelumääriin, arvioihin tai ongelmamittareihin.

## Yleiset sudenkuopat

<AccordionGroup>
  <Accordion title="Agentti ei koskaan kutsu työkalua">
    LLM tekee päätöksen työkalun kuvauksen perusteella. Jos soittajan
    kysymys ei vastaa kuvausta, malli ei kutsu työkalua. Täsmennä kuvausta
    (lisää yleisiä synonyymeja ja sanamuotoja) tai mainitse se suoraan
    agentin kehotteessa ("Kun soittaja kysyy säästä, käytä
    `get_weather`-toimintoa.").
  </Accordion>

  <Accordion title="Työkalu palauttaa liikaa dataa">
    Yli 6 kB:n vastaukset katkaistaan litteroinnin esikatselussa. Palauta
    vain kentät, joita LLM tarvitsee — älä koko tietuettasi.
  </Accordion>

  <Accordion title="Aikakatkaisut">
    Työkalupäätepisteiden oletusaikakatkaisu on 10 sekuntia. Jos tarvitset
    enemmän aikaa, käsittele pyyntö asynkronisesti: palauta `{"status": "pending", "request_id": "..."}`
    ja tuo tulos esiin erillisellä työkalukutsulla.
  </Accordion>

  <Accordion title="Versiointi">
    Jokainen integraation `PATCH` luo uuden revision. Tarkista
    [`GET /v1/integrations/{id}/versions`](/api-reference/integrations#version-history)
    nähdäksesi, kuka muutti mitäkin. Jos rikot työkalun skeeman, voit
    palauttaa sen manuaalisesti lähettämällä vanhemman tilannekuvan takaisin PATCH-pyynnöllä.
  </Accordion>
</AccordionGroup>

---

## Seuraavat vaiheet

<CardGroup cols={2}>
  <Card title="Integraatioiden viite" icon="plug" href="/api-reference/integrations">
    CRUD, siirto, versiohistoria.
  </Card>
  <Card title="Function Tools -määritys" icon="screwdriver-wrench" href="/fi/tools/overview">
    Koko JSON-skeeman kielioppi ja allekirjoitettujen päätepisteiden sopimus.
  </Card>
  <Card title="Vahvista allekirjoitukset" icon="shield-check" href="/fi/guides/verify-webhook-signatures">
    Käytä webhook-allekirjoitusmallia työkalujen päätepisteisiin.
  </Card>
  <Card title="Puhtaaksikirjoitus- ja historia-API" icon="phone" href="/api-reference/calls">
    Tarkastele työkalukutsun koko edestakaista kulkua.
  </Card>
</CardGroup>
