Open in
Funksjonsverktøy
Gi AI-agentene dine funksjonsverktøy som kaller eksterne API-er midt i samtalen – hent kundedata, bestill avtaler, oppdater oppføringer – med typede parametere.
Funksjonsverktøy lar stemmeagentene dine kalle eksterne API-er under telefonsamtaler. Bruk dem til å slå opp kundedata, sjekke tilgjengelighet, bestille avtaler eller utføre enhver handling backend-en din støtter.
Slik fungerer det
- Du definerer verktøy med et skjema (hvilke argumenter verktøyet godtar)
- Du oppgir en
endpoint-konfigurasjon (der ThunderPhone kaller API-et ditt) — eller utelater den for å motta verktøykall på organisasjonens webhook - Under en samtale avgjør AI-en når den skal bruke et verktøy basert på samtalen
- ThunderPhone kaller endepunktet ditt med verktøyargumentene
- API-svaret ditt mates tilbake til AI-en for å fortsette samtalen
| Mulighet | Hvor det kjører | Oppsett |
|---|---|---|
| Innebygde verktøy | ThunderPhone | Promptinstruksjoner; enkelte verktøy trenger også en agentinnstilling |
| Appkoblinger | ThunderPhone og den tilkoblede leverandøren | Koble til kontoen og legg til godkjente handlinger |
| API-koblinger og funksjonsverktøy | HTTP API-et ditt | Definer endepunktet og skjemaet, eller motta funksjonskall via en webhook |
| MCP-servere | En ekstern MCP-server | Legg til serveren, oppdag verktøyene og legg den til agenten |
Verktøyskjema
Hvert verktøy følger denne strukturen:
{
"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
}Verktøykonfigurasjon
| Felt | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
timeout | tall | Nei | Maksimal kjøretid i sekunder (standard: 20, maksimum: 180) |
Funksjonsdefinisjon
| Felt | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
name | streng | Ja | Unik identifikator for verktøyet |
description | streng | Ja | Forklarer AI-en når dette verktøyet skal brukes |
parameters | objekt | Ja | JSON Schema for verktøyargumenter |
Endepunktkonfigurasjon
| Felt | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
url | streng | Ja | URL-en til API-endepunktet ditt |
method | streng | Nei | HTTP-metode (standard: POST) |
headers | objekt | Nei | Egendefinerte headere som skal inkluderes |
To kallbaner
Hvilken forespørsel serveren din mottar, avhenger av om verktøyet har et
endpoint:
Verktøy med endpoint | Verktøy uten endpoint | |
|---|---|---|
| Hvor forespørselen sendes | Direkte til endpoint.url | Organisasjonens eldre webhook-URL |
| Brødtekst | Valgt forespørselsformat (rene argumenter som standard) | telephony.tool / web.tool-omslag |
| Headere | Dine endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature |
| Signeringsnøkkel | Organisasjonens webhook-hemmelighet | Organisasjonens webhook-hemmelighet |
Begge banene er blokkerende — AI-en venter midt i en setning på
resultatet. Standard tidsavbrudd er 20 s; angi verktøyets øverste
timeout for å tillate lengre kjøretid, opptil plattformens maksimum på
180 s. Hold behandlere raske. En blanding fungerer fint:
I en samtale der organisasjonen har en webhook-URL, kalles verktøy med et endpoint
direkte, mens resten faller tilbake til webhooken.
Direkte endepunktkall
Når stemmeagenten kaller et verktøy som har et endpoint, sender ThunderPhone
en forespørsel til URL-en din:
Forespørselsoverskrifter
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-keyEgendefinerte headere fra endpoint.headers inkluderes alltid
ordrett, i tillegg til disse ThunderPhone-navngitte headerne:
X-ThunderPhone-Signature-V2— tidsstemplet HMAC-SHA256 over metode, sti, spørring og brødtekst, med din organisasjons webhook-hemmelighet som nøkkel. Verifiser denne og avvis forespørsler som er eldre enn 5 minutter. Se Verifiser webhook-signaturerX-ThunderPhone-Signature— eldre HMAC-SHA256 av de nøyaktige bytene i forespørselsbrødteksten, med samme nøkkel, fortsatt sendt for eksisterende verifikatorerX-ThunderPhone-Call-ID— ID-en for gjeldende samtale
Content-Type: application/json angis med mindre endpoint.headers
overstyrer den — en egendefinert Content-Type har forrang.
Forespørselsformat
Hver API-tilkobling har en request_format-innstilling. Velg vapi eller
retell når et importert verktøy skal fortsette å kalle et endepunkt som er bygget for
den plattformen. Nye og eksisterende tilkoblinger bruker standard som standard.
For POST / PUT / PATCH serialiserer ThunderPhone den valgte
konvolutten kanonisk (sorterte nøkler, kompakte skilletegn). Begge signaturene
dekker nøyaktig disse bytene.
Standard
standard sender bare verktøyargumentene, uten innpakning. Dette er
standardinnstillingen og bevarer ThunderPhone sin opprinnelige forespørselskropp byte for byte:
{"date":"2025-01-02","service":"consultation"}Vapi
vapi sender Vapis tool-calls-servermelding
i formen Vapi dokumenterer. call.id er ThunderPhone-anrops-ID-en. Verktøykallets
id er unik for påkallingen og brukes på nytt til å matche
endepunktets resultat. Kallet vises i både toolCallList og
toolWithToolCallList, med function.arguments som et JSON-objekt:
{
"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-spesifikke felt som assistant, artifact og det fullstendige call-objektet
sendes ikke.
Returner Vapis svarkonvolutt med samsvarende verktøykall-ID:
{
"results": [
{
"toolCallId": "call_00112233445566778899aabbccddeeff",
"result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
}
]
}ThunderPhone gir AI-en den utpakkede result-strengen. Den godtar også en
JSON-verdi for kompatibilitet med endepunkter som allerede returnerer en. En
error i stedet for result returneres til AI-en som en verktøyfeil. Hvis
endepunktet returnerer en feilformatert eller ikke-samsvarende Vapi-konvolutt, logger ThunderPhone
en advarsel og faller tilbake til standard svarbehandling i stedet for å avbryte
anropet.
Retell
retell sender forespørselen som er dokumentert for en egendefinert Retell-
funksjon:
{
"name": "search_appointments",
"call": { "call_id": "987654321" },
"args": { "date": "2025-01-02", "service": "consultation" }
}call-objektet inkluderer bare call_id. ThunderPhone inkluderer ikke
Retell-spesifikke felt den ikke kan oppgi korrekt ved utsending, for eksempel
agent_id, transcript, transcript_object, metadata eller dynamiske
variabler. Retell godtar enhver svartekst; ThunderPhone sender den videre
med standard svarbehandling.
For GET / DELETE sendes argumentene som spørringsparametere
og brødteksten er tom uavhengig av request_format. V2-signaturen
dekker spørringsstrengen slik den sendes; den eldre signaturen beregnes over
den tomme bytestrengen. Se
Verifiser webhook-signaturer.
Svar
Returner et JSON-svar med verktøyresultatet:
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}Svaret formateres og gis til stemmeagenten for å fortsette
samtalen. Svar som ikke er JSON, pakkes inn som {"data": "<text>"};
tidsavbrudd og tilkoblingsfeil rapporteres til stemmeagenten som feil, slik
at agenten kan beklage og gå videre i stedet for å stoppe opp.
Ruting i webhook-modus
Verktøy uten et endpoint rutes til organisasjonens eldre
webhook-URL som en signert telephony.tool-forespørsel (telefonanrop) eller
web.tool-forespørsel (nettanrop). I motsetning til revisjonsvarslene
som leveres til webhook-endepunkter etter utførelse, er denne forespørselen
selve utførelsen — HTTP-svaret ditt er verktøyresultatet.
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}web.tool inneholder origin_domain i stedet for from_number /
to_number. Svar med verktøyresultatet som JSON — samme svarkontrakt
som ved direkte endepunktkall. Forespørselen er signert med organisasjonens
webhook-hemmelighet, med begge signaturheaderne, som alle andre webhooks.
Signaturverifisering
Direkte verktøykall signeres på samme måte som webhooks, med organisasjonens webhook-hemmelighet som nøkkel:
X-ThunderPhone-Signature-V2signerer tidsstempelet, metoden, banen og spørringen slik de sendes, samt de nøyaktige byteverdiene i brødteksten. Avvis forespørsler der tidsstempelet avviker med mer enn 5 minutter fra klokken din.X-ThunderPhone-Signature(eldre) signerer bare byteverdiene i brødteksten, den tomme bytestrengen forGET/DELETE. Den sendes fortsatt, uendret.
SDK-hjelpefunksjonene kontrollerer V2-headeren, inkludert 5-minuttersvinduet:
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}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 });
});Fullstendige oppskrifter — den signerte strengen, et gjennomarbeidet eksempel, kode uten
SDK-et, tilfellet GET / DELETE og forbeholdet om ingen hemmelighet — finner du i Verifiser webhook-signaturer.
Eksempel: Fullstendig bestillingsflyt
Her er et sett med verktøy for et komplett system for timebestilling:
{
"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" }
}
}
]
}Beste praksis
Skriv tydelige beskrivelser
Feltet description hjelper AI-en med å forstå når verktøyet skal brukes. Vær spesifikk om hva det gjør, og når det passer å bruke det.
Håndter feil på en god måte
Returner feilmeldinger AI-en kan forstå: {"error": "No slots available for that date"} i stedet for generiske 500-feil.
Hold svarene korte
Returner bare det AI-en trenger for å fortsette samtalen. Store nyttelaster gir tregere responstider.
Bruk obligatoriske felt med omtanke
Merk felt som required bare når det er helt nødvendig. AI-en vil be brukeren om obligatorisk informasjon før den kaller verktøyet.
Relatert
Be plattformadministrerte samtalehandlinger uten å definere et endepunkt.
Plattformadministrerte verktøy for HubSpot, Salesforce, Slack, Google Kalender, Google Regneark og Cal.com — ingen endepunkt kreves.
Koble til en MCP-server og la agenten kalle verktøyene dens.
Gjenbrukbare REST-integrasjoner du kan koble til agenter.
Én verifiseringshjelper for webhooks og verktøykall.