Open in
Outils de fonction
Équipez vos agents vocaux IA d’outils de fonction qui appellent des API externes en cours de conversation — récupérer des données client, prendre des rendez-vous, mettre à jour des dossiers — avec des paramètres typés.
Les outils de fonction permettent à vos agents IA d'appeler des API externes pendant les appels téléphoniques. Utilisez-les pour rechercher des données client, vérifier les disponibilités, prendre des rendez-vous ou effectuer toute action prise en charge par votre backend.
Fonctionnement
- Définissez des outils avec un schéma (les arguments acceptés par l'outil)
- Fournissez une configuration
endpoint(l'emplacement où ThunderPhone appelle votre API) — ou omettez-la pour recevoir les appels d'outils sur le webhook de votre organisation - Pendant un appel, l'IA décide quand utiliser un outil en fonction de la conversation
- ThunderPhone appelle votre endpoint avec les arguments de l'outil
- La réponse de votre API est renvoyée à l'IA pour poursuivre la conversation
| Fonctionnalité | Emplacement d'exécution | Configuration |
|---|---|---|
| Outils intégrés | ThunderPhone | Instructions dans le prompt ; certains outils nécessitent également un paramètre d'agent |
| Connexions d'applications | ThunderPhone et le fournisseur connecté | Connectez le compte et associez les actions approuvées |
| Connexions API et outils de fonction | Votre API HTTP | Définissez l'endpoint et le schéma, ou recevez les appels de fonction via un webhook |
| Serveurs MCP | Un serveur MCP distant | Ajoutez le serveur, découvrez ses outils et associez-le à l'agent |
Schéma d'outil
Chaque outil suit cette structure :
{
"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
}Configuration de l'outil
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
timeout | nombre | Non | Durée d'exécution maximale en secondes (valeur par défaut : 20, maximum : 180) |
Définition de fonction
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
name | chaîne | Oui | Identifiant unique de l'outil |
description | chaîne | Oui | Indique à l'IA quand utiliser cet outil |
parameters | objet | Oui | Schéma JSON des arguments de l'outil |
Configuration de l'endpoint
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
url | chaîne | Oui | URL de l'endpoint de votre API |
method | chaîne | Non | Méthode HTTP (valeur par défaut : POST) |
headers | objet | Non | En-têtes personnalisés à inclure |
Deux chemins d'invocation
La requête reçue par votre serveur dépend de la présence ou non d'un
endpoint pour l'outil :
Outil avec endpoint | Outil sans endpoint | |
|---|---|---|
| Destination de la requête | Directement vers endpoint.url | URL webhook héritée de votre organisation |
| Corps | Format de requête sélectionné (arguments bruts par défaut) | Enveloppe telephony.tool / web.tool |
| En-têtes | Vos endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature |
| Clé de signature | Secret webhook de l’organisation | Secret webhook de l’organisation |
Les deux chemins sont bloquants — l'IA attend le résultat au milieu
d'une phrase. Le délai d'attente par défaut est de 20 s ; définissez
le timeout de niveau supérieur de l'outil pour autoriser une exécution
plus longue, jusqu'au maximum de la plateforme de 180 s. Gardez les
handlers rapides. Un mélange est possible :
lors d'un appel dont l'organisation dispose d'une URL webhook, les outils avec un endpoint sont
appelés directement et les autres utilisent le webhook.
Appels directs à un endpoint
Lorsque l’IA invoque un outil doté d’un endpoint, ThunderPhone envoie
une requête à votre URL :
En-têtes de requête
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-keyLes en-têtes personnalisés de votre endpoint.headers sont toujours inclus
tels quels, ainsi que ces en-têtes avec espace de noms ThunderPhone :
X-ThunderPhone-Signature-V2— HMAC-SHA256 horodaté couvrant la méthode, le chemin, la requête et le corps, utilisant comme clé votre secret webhook d'organisation. Vérifiez celui-ci et rejetez les requêtes datant de plus de 5 minutes ; voir Vérifier les signatures webhookX-ThunderPhone-Signature— HMAC-SHA256 hérité des octets exacts du corps de la requête, avec la même clé, toujours envoyé pour les vérificateurs existantsX-ThunderPhone-Call-ID— L'ID de l'appel en cours
Content-Type: application/json est défini sauf si votre endpoint.headers
le remplace — un Content-Type personnalisé prévaut.
Format de requête
Chaque connexion API dispose d’un paramètre request_format. Choisissez vapi ou
retell lorsqu’un outil importé doit continuer à appeler un point de terminaison conçu pour
cette plateforme. Les nouvelles connexions comme les connexions existantes utilisent standard par défaut.
Pour POST / PUT / PATCH, ThunderPhone sérialise l’enveloppe sélectionnée
de manière canonique (clés triées, séparateurs compacts). Les deux signatures
couvrent ces octets exacts.
Standard
standard envoie uniquement les arguments de l’outil, sans enveloppe. Il s’agit du
comportement par défaut et il préserve le corps de requête d’origine de ThunderPhone octet pour octet :
{"date":"2025-01-02","service":"consultation"}Vapi
vapi envoie le message serveur tool-calls de Vapi
dans le format documenté par Vapi. Le call.id est l’ID d’appel ThunderPhone. L’id
de l’appel d’outil est unique à l’invocation et est réutilisé pour associer le
résultat du point de terminaison. L’appel apparaît dans toolCallList et
toolWithToolCallList, avec function.arguments sous forme d’objet 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" }
}
}
}
]
}
}Les champs propres à Vapi, tels que assistant, artifact et l’objet call
complet, ne sont pas envoyés.
Renvoyez l’enveloppe de réponse Vapi avec l’ID d’appel d’outil correspondant :
{
"results": [
{
"toolCallId": "call_00112233445566778899aabbccddeeff",
"result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
}
]
}ThunderPhone fournit à l’IA la chaîne result non encapsulée. Il accepte également une
valeur JSON pour assurer la compatibilité avec les points de terminaison qui en renvoient déjà une. Une
valeur error à la place de result est renvoyée à l’IA comme une erreur d’outil. Si le
point de terminaison renvoie une enveloppe Vapi mal formée ou non correspondante, ThunderPhone enregistre
un avertissement et utilise l’analyse standard des réponses au lieu de faire échouer
l’appel.
Retell
retell envoie la requête documentée pour une fonction personnalisée
Retell :
{
"name": "search_appointments",
"call": { "call_id": "987654321" },
"args": { "date": "2025-01-02", "service": "consultation" }
}L’objet call inclut uniquement call_id. ThunderPhone n’inclut pas les
champs propres à Retell qu’il ne peut pas fournir honnêtement lors de l’envoi, tels que
agent_id, transcript, transcript_object, metadata ou les variables
dynamiques. Retell accepte n’importe quel corps de réponse ; ThunderPhone le transmet
en utilisant la gestion standard des réponses.
Pour GET / DELETE, les arguments sont envoyés sous forme de paramètres de requête
et le corps est vide, quelle que soit la valeur de request_format. La signature V2
couvre la chaîne de requête telle qu’elle est envoyée ; la signature héritée est calculée sur
la chaîne d’octets vide. Consultez
Vérifier les signatures des webhooks.
Réponse
Renvoyez une réponse JSON contenant le résultat de l’outil :
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}La réponse est formatée et fournie à l’IA afin de poursuivre la
conversation. Les réponses non JSON sont encapsulées sous la forme {"data": "<text>"} ;
les délais d’expiration et les échecs de connexion sont signalés à l’IA comme des erreurs,
afin que l’agent puisse s’excuser et poursuivre plutôt que de rester bloqué.
Envoi en mode webhook
Les outils sans endpoint sont envoyés à l’URL de webhook historique de votre
organisation sous forme de requête signée telephony.tool (appels téléphoniques) ou web.tool
(appels web). Contrairement aux notifications d’audit
envoyées aux endpoints de webhook après l’exécution, cette requête est
l’exécution — votre réponse HTTP constitue le résultat de l’outil.
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}web.tool contient origin_domain au lieu de from_number /
to_number. Répondez avec le résultat de l’outil au format JSON — le même contrat de réponse que pour les appels directs à un endpoint. La requête est signée avec le secret webhook de l’organisation, avec les deux en-têtes de signature, comme tout autre webhook.
Vérification de signature
Les appels directs d'outils sont signés de la même manière que les webhooks, à l'aide du secret webhook de votre organisation :
X-ThunderPhone-Signature-V2signe l'horodatage, la méthode, le chemin et la requête tels qu'ils sont envoyés, ainsi que les octets exacts du corps. Rejetez les requêtes dont l'horodatage s'écarte de plus de 5 minutes de votre horloge.X-ThunderPhone-Signature(hérité) signe uniquement les octets du corps, la chaîne d'octets vide pourGET/DELETE. Il est toujours envoyé, sans modification.
Les assistants SDK vérifient l'en-tête V2, y compris la fenêtre de 5 minutes :
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 });
});Les guides complets — la chaîne signée, un exemple détaillé, du code sans
SDK, le cas GET / DELETE et l'avertissement concernant l'absence de secret — se trouvent dans Vérifier les signatures webhook.
Exemple : flux de réservation complet
Voici un ensemble d’outils pour un système complet de réservation de rendez-vous :
{
"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" }
}
}
]
}Bonnes pratiques
Rédiger des descriptions claires
Le champ description aide l’IA à comprendre quand utiliser l’outil. Indiquez précisément ce qu’il fait et quand il est approprié de l’utiliser.
Gérer les erreurs avec élégance
Renvoyez des messages d’erreur que l’IA peut comprendre : {"error": "No slots available for that date"} plutôt que des erreurs 500 génériques.
Garder les réponses concises
Renvoyez uniquement ce dont l’IA a besoin pour poursuivre la conversation. Les charges utiles volumineuses ralentissent les temps de réponse.
Utiliser les champs obligatoires avec discernement
Marquez les champs comme required uniquement lorsque cela est réellement nécessaire. L’IA demandera à l’utilisateur les informations obligatoires avant d’appeler l’outil.
Contenu associé
Déclenchez des actions d’appel gérées par la plateforme sans définir de point de terminaison.
Outils gérés par la plateforme pour HubSpot, Salesforce, Slack, Google Calendar, Google Sheets et Cal.com — aucun point de terminaison requis.
Connectez un serveur MCP et laissez l’agent appeler ses outils.
Intégrations REST réutilisables que vous pouvez associer à des agents.
Un assistant de vérification unique pour les webhooks et les appels d’outils.