Funktionsverktyg
Ge dina AI-agenter funktionsverktyg som anropar externa API:er mitt i samtalet — hämta kunddata, boka tider, uppdatera poster — med typade parametrar.
Funktionsverktyg gör det möjligt för dina AI-agenter att anropa externa API:er under telefonsamtal. Använd dem för att slå upp kunddata, kontrollera tillgänglighet, boka möten eller utföra valfri åtgärd som din backend stöder.
Så fungerar det
- Du definierar verktyg med ett schema (vilka argument verktyget accepterar)
- Du anger en
endpoint-konfiguration (där ThunderPhone anropar ditt API) — eller utelämnar den för att ta emot verktygsanrop på din organisations webhook - Under ett samtal avgör AI:n när ett verktyg ska användas baserat på konversationen
- ThunderPhone anropar din endpoint med verktygsargumenten
- Ditt API-svar skickas tillbaka till AI:n för att fortsätta konversationen
Verktygsschema
Varje verktyg följer denna struktur:
{
"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
}Verktygskonfiguration
| Fält | Typ | Krävs | Beskrivning |
|---|---|---|---|
timeout | number | Nej | Maximal körningstid i sekunder (standard: 20, maximalt: 180) |
Funktionsdefinition
| Fält | Typ | Krävs | Beskrivning |
|---|---|---|---|
name | string | Ja | Unik identifierare för verktyget |
description | string | Ja | Förklarar för AI:n när verktyget ska användas |
parameters | object | Ja | JSON Schema för verktygsargument |
Endpoint-konfiguration
| Fält | Typ | Krävs | Beskrivning |
|---|---|---|---|
url | string | Ja | URL:en för din API-endpoint |
method | string | Nej | HTTP-metod (standard: POST) |
headers | object | Nej | Anpassade headers att inkludera |
Två anropsvägar
Vilken begäran din server tar emot beror på om verktyget har en
endpoint:
Verktyg med endpoint | Verktyg utan endpoint | |
|---|---|---|
| Vart begäran skickas | Direkt till endpoint.url | Din organisations äldre webhook-URL |
| Innehåll | Endast verktygsargument | telephony.tool / web.tool-omslag |
| HTTP-huvuden | Dina endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature |
| Signeringsnyckel | Organisationens webhook-hemlighet | Organisationens webhook-hemlighet |
Båda vägarna är blockerande — AI:n väntar mitt i en mening på
resultatet. Standardtimeouten är 20 s; ange verktygets timeout
på toppnivå för att tillåta en längre körningstid, upp till plattformens
maxgräns på 180 s. Håll hanterare snabba. Du kan blanda dem:
i ett samtal där organisationen har en webhook-URL anropas verktyg med en
endpoint direkt, medan övriga faller tillbaka till webhooken.
Direkta endpointanrop
När AI:n anropar ett verktyg som har ett endpoint skickar ThunderPhone
en begäran till din URL:
Begärandehuvuden
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-keyAnpassade huvuden från ditt endpoint.headers inkluderas alltid
ordagrant, tillsammans med två ThunderPhone-namnområdesindelade huvuden:
X-ThunderPhone-Signature— HMAC-SHA256 av de exakta bytevärdena i begärandetexten, med din organisations webhookhemlighet som nyckelX-ThunderPhone-Call-ID— ID:t för det aktuella samtalet
Content-Type: application/json anges om det inte åsidosätts av ditt
endpoint.headers — en anpassad Content-Type har företräde.
Begärandetext
För POST / PUT / PATCH innehåller texten endast verktygsargumenten
(inget omslag), serialiserade kanoniskt (sorterade nycklar, kompakta
avgränsare):
{"date":"2025-01-02","service":"consultation"}För GET / DELETE skickas argumenten som frågeparametrar
och texten är tom — signaturen beräknas då över den tomma
bytesträngen. Se
Verifiera webhooksignaturer.
Svar
Returnera ett JSON-svar med verktygsresultatet:
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}Svaret formateras och skickas till AI:n för att fortsätta
konversationen. Icke-JSON-svar omsluts som {"data": "<text>"};
tidsgränser och anslutningsfel rapporteras till AI:n som fel, så att
agenten kan be om ursäkt och gå vidare i stället för att fastna.
Utskick i webhookläge
Verktyg utan ett endpoint skickas till organisationens äldre
webhook-URL som en signerad telephony.tool-begäran (telefonsamtal) eller
web.tool-begäran (webbsamtal). Till skillnad från granskningsnotiserna
som levereras till webhook-endpoints efter körning, är denna begäran
körningen — ditt HTTP-svar är verktygsresultatet.
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}web.tool innehåller origin_domain i stället för from_number /
to_number. Svara med verktygsresultatet som JSON — samma svarskontrakt
som för direkta endpointanrop. Begäran signeras med organisationens
webhookhemlighet över den råa texten, precis som alla andra webhookar.
Signaturverifiering
Direkta verktygsanrop signeras på samma sätt som webhooks:
- HMAC-SHA256 över de exakta bytevärdena i förfrågningstexten (det kanoniska JSON-formatet — sorterade nycklar, inga extra blanksteg)
- Signeras med din organisations webhook-hemlighet
- Verktyg med
GET/DELETEsignerar den tomma bytesträngen
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}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 });
});Kompletta exempel — inklusive fallet med tom förfrågningstext och information om när ingen hemlighet har angetts — finns i Verifiera webhook-signaturer.
Exempel: Komplett bokningsflöde
Här är en uppsättning verktyg för ett komplett system för tidsbokning:
{
"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" }
}
}
]
}Bästa praxis
Skriv tydliga beskrivningar
Fältet description hjälper AI:n att förstå när verktyget ska användas. Var specifik om vad det gör och när det är lämpligt.
Hantera fel smidigt
Returnera felmeddelanden som AI:n kan förstå: {"error": "No slots available for that date"} i stället för generiska 500-fel.
Håll svaren kortfattade
Returnera endast det AI:n behöver för att fortsätta samtalet. Stora nyttolaster förlänger svarstiderna.
Använd obligatoriska fält med omdöme
Markera fält som required endast när det verkligen behövs. AI:n ber användaren om obligatorisk information innan verktyget anropas.
Relaterat
Plattformshanterade verktyg för HubSpot, Salesforce, Slack, Google Kalender, Google Kalkylark och Cal.com — ingen endpoint krävs.
Anslut en MCP-server och låt agenten anropa dess verktyg.
Återanvändbara REST-integrationer som du kan ansluta till agenter.
En verifieringshjälp för webhooks och verktygsanrop.