Open in
Alat Fungsi
Berikan alat fungsi kepada agen AI Anda yang memanggil API eksternal di tengah percakapan — mengambil data pelanggan, menjadwalkan janji temu, memperbarui catatan — dengan parameter bertipe.
Alat fungsi memungkinkan agen AI Anda memanggil API eksternal selama panggilan telepon. Gunakan untuk mencari data pelanggan, memeriksa ketersediaan, menjadwalkan janji temu, atau menjalankan tindakan apa pun yang didukung backend Anda.
Cara Kerjanya
- Tentukan alat dengan skema (argumen yang diterima alat)
- Sediakan konfigurasi
endpoint(tempat ThunderPhone memanggil API Anda) — atau biarkan kosong untuk menerima panggilan alat pada webhook organisasi Anda - Selama panggilan, AI memutuskan kapan menggunakan alat berdasarkan percakapan
- ThunderPhone memanggil endpoint Anda dengan argumen alat
- Respons API Anda dikirim kembali ke AI untuk melanjutkan percakapan
| Kemampuan | Tempat dijalankan | Penyiapan |
|---|---|---|
| Alat bawaan | ThunderPhone | Instruksi Prompt; beberapa alat juga memerlukan pengaturan agen |
| Koneksi aplikasi | ThunderPhone dan penyedia yang terhubung | Hubungkan akun dan lampirkan tindakan yang disetujui |
| Koneksi API dan alat fungsi | API HTTP Anda | Tentukan endpoint dan skema, atau terima panggilan fungsi melalui webhook |
| Server MCP | Server MCP jarak jauh | Tambahkan server, temukan alatnya, lalu lampirkan ke agen |
Skema Alat
Setiap alat mengikuti struktur ini:
{
"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
}Konfigurasi Alat
| Kolom | Tipe | Wajib | Deskripsi |
|---|---|---|---|
timeout | number | Tidak | Waktu eksekusi maksimum dalam detik (default: 20, maksimum: 180) |
Definisi Fungsi
| Kolom | Tipe | Wajib | Deskripsi |
|---|---|---|---|
name | string | Ya | Pengenal unik untuk alat |
description | string | Ya | Menjelaskan kepada AI kapan alat ini digunakan |
parameters | object | Ya | Skema JSON untuk argumen alat |
Konfigurasi Endpoint
| Kolom | Tipe | Wajib | Deskripsi |
|---|---|---|---|
url | string | Ya | URL endpoint API Anda |
method | string | Tidak | Metode HTTP (default: POST) |
headers | object | Tidak | Header khusus yang akan disertakan |
Dua jalur pemanggilan
Permintaan yang diterima server Anda bergantung pada apakah alat memiliki
endpoint:
Tool dengan endpoint | Tool tanpa endpoint | |
|---|---|---|
| Tujuan permintaan | Langsung ke endpoint.url | URL webhook lama organisasi Anda |
| Isi | Format permintaan yang dipilih (argumen tanpa pembungkus secara default) | Pembungkus telephony.tool / web.tool |
| Header | endpoint.headers Anda + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature |
| Kunci penandatanganan | Rahasia webhook organisasi | Rahasia webhook organisasi |
Kedua jalur bersifat memblokir — AI menunggu hasilnya di tengah
kalimat. Batas waktu default adalah 20 d; atur timeout tingkat atas
pada alat untuk mengizinkan eksekusi yang lebih lama, hingga batas maksimum
Platform 180 d. Pastikan handler tetap cepat. Kombinasi keduanya dapat digunakan:
pada panggilan yang organisasinya memiliki URL webhook, alat dengan endpoint
dipanggil secara langsung dan sisanya dialihkan ke webhook.
Panggilan endpoint langsung
Saat AI memanggil alat yang memiliki endpoint, ThunderPhone mengirim
permintaan ke URL Anda:
Header Permintaan
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-keyHeader kustom dari endpoint.headers Anda selalu disertakan
apa adanya, ditambah header dengan namespace ThunderPhone berikut:
X-ThunderPhone-Signature-V2— HMAC-SHA256 bertanda waktu atas metode, path, kueri, dan body, yang menggunakan secret webhook organisasi Anda. Verifikasi header ini dan tolak permintaan yang berusia lebih dari 5 menit; lihat Verifikasi signature webhookX-ThunderPhone-Signature— HMAC-SHA256 lama dari byte body permintaan yang persis sama, dengan kunci yang sama, masih dikirim untuk verifier yang adaX-ThunderPhone-Call-ID— ID panggilan saat ini
Content-Type: application/json ditetapkan kecuali endpoint.headers
Anda menggantinya — Content-Type kustom akan digunakan.
Format permintaan
Setiap koneksi API memiliki pengaturan request_format. Pilih vapi atau
retell ketika tool yang diimpor harus tetap memanggil endpoint yang dibuat untuk
platform tersebut. Koneksi baru dan yang sudah ada secara default menggunakan standard.
Untuk POST / PUT / PATCH, ThunderPhone membuat serialisasi
envelope yang dipilih secara kanonis (kunci diurutkan, pemisah ringkas). Kedua tanda tangan
mencakup byte yang tepat ini.
Standard
standard hanya mengirim argumen alat, tanpa wrapper. Ini adalah default dan mempertahankan isi permintaan asli ThunderPhone byte demi byte:
{"date":"2025-01-02","service":"consultation"}Vapi
vapi mengirim pesan server tool-calls Vapi
dalam bentuk yang didokumentasikan Vapi. call.id adalah ID panggilan ThunderPhone. id
tool-call bersifat unik untuk pemanggilan tersebut dan digunakan kembali untuk mencocokkan
hasil endpoint. Panggilan muncul di toolCallList dan
toolWithToolCallList, dengan function.arguments sebagai objek 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" }
}
}
}
]
}
}Kolom khusus Vapi seperti assistant, artifact, dan objek call lengkap
tidak dikirim.
Kembalikan envelope respons Vapi dengan ID tool-call yang sesuai:
{
"results": [
{
"toolCallId": "call_00112233445566778899aabbccddeeff",
"result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
}
]
}ThunderPhone memberikan string result tanpa pembungkus kepada AI. ThunderPhone juga menerima
nilai JSON untuk kompatibilitas dengan endpoint yang sudah mengembalikannya. error
sebagai pengganti result dikembalikan kepada AI sebagai error tool. Jika
endpoint mengembalikan envelope Vapi yang tidak valid atau tidak cocok, ThunderPhone mencatat
peringatan dan beralih ke parsing respons standarnya alih-alih menggagalkan
panggilan.
Retell
retell mengirim permintaan yang didokumentasikan untuk fungsi kustom
Retell:
{
"name": "search_appointments",
"call": { "call_id": "987654321" },
"args": { "date": "2025-01-02", "service": "consultation" }
}Objek call hanya menyertakan call_id. ThunderPhone tidak menyertakan
kolom khusus Retell yang tidak dapat disediakannya secara akurat saat pengiriman, seperti
agent_id, transcript, transcript_object, metadata, atau variabel
dinamis. Retell menerima isi respons apa pun; ThunderPhone meneruskannya
menggunakan penanganan respons standar.
Untuk GET / DELETE, argumen dikirim sebagai parameter kueri
dan isi permintaan kosong terlepas dari request_format. Tanda tangan V2
mencakup string kueri sebagaimana dikirim; tanda tangan lama dihitung berdasarkan
string byte kosong. Lihat
Verifikasi tanda tangan webhook.
Respons
Kembalikan respons JSON dengan hasil alat:
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}Respons diformat dan diberikan kepada AI untuk melanjutkan
percakapan. Respons non-JSON dibungkus sebagai {"data": "<text>"};
waktu habis dan kegagalan koneksi dilaporkan kepada AI sebagai kesalahan, sehingga
agen dapat meminta maaf dan melanjutkan alih-alih terhenti.
Pengiriman mode webhook
Alat tanpa endpoint dikirim ke URL webhook lama organisasi Anda
sebagai permintaan telephony.tool (panggilan telepon) atau web.tool
(panggilan web) yang ditandatangani. Berbeda dengan notifikasi audit
yang dikirimkan ke endpoint webhook setelah eksekusi, permintaan ini adalah
eksekusinya — respons HTTP Anda adalah hasil alat.
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}web.tool membawa origin_domain alih-alih from_number /
to_number. Tanggapi dengan hasil tool sebagai JSON — kontrak respons yang sama
seperti panggilan endpoint langsung. Permintaan ditandatangani dengan rahasia webhook organisasi, menggunakan kedua header tanda tangan, seperti setiap webhook lainnya.
Verifikasi Tanda Tangan
Panggilan tool langsung ditandatangani dengan cara yang sama seperti webhook, menggunakan rahasia webhook organisasi Anda:
X-ThunderPhone-Signature-V2menandatangani stempel waktu, metode, path, dan query sebagaimana dikirim, serta byte body yang tepat. Tolak permintaan yang stempel waktunya berjarak lebih dari 5 menit dari jam Anda.X-ThunderPhone-Signature(legacy) hanya menandatangani byte body, yaitu string byte kosong untukGET/DELETE. Header ini tetap dikirim, tanpa perubahan.
Helper SDK memeriksa header V2, termasuk jangka waktu 5 menit:
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 });
});Panduan lengkap — string yang ditandatangani, contoh yang dikerjakan, kode tanpa
SDK, kasus GET / DELETE, dan catatan tanpa rahasia — tersedia di Verifikasi tanda tangan webhook.
Contoh: Alur Pemesanan Lengkap
Berikut adalah serangkaian alat untuk sistem pemesanan janji temu lengkap:
{
"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" }
}
}
]
}Praktik Terbaik
Tulis deskripsi yang jelas
Kolom description membantu AI memahami kapan harus menggunakan alat tersebut. Jelaskan secara spesifik apa fungsinya dan kapan alat tersebut sesuai digunakan.
Tangani error dengan baik
Kembalikan pesan error yang dapat dipahami AI: {"error": "No slots available for that date"} alih-alih error 500 generik.
Jaga respons tetap ringkas
Kembalikan hanya informasi yang diperlukan AI untuk melanjutkan percakapan. Payload besar memperlambat waktu respons.
Gunakan kolom wajib dengan bijak
Tandai kolom sebagai required hanya jika benar-benar diperlukan. AI akan meminta informasi wajib dari pengguna sebelum memanggil alat.
Terkait
Arahkan tindakan panggilan yang dikelola Platform tanpa menentukan endpoint.
Alat yang dikelola Platform untuk HubSpot, Salesforce, Slack, Google Calendar, Google Sheets, dan Cal.com — tanpa endpoint.
Lampirkan server MCP dan biarkan agen memanggil alatnya.
Integrasi REST yang dapat digunakan kembali dan dapat Anda lampirkan ke agen.
Satu helper verifikasi untuk webhook dan panggilan alat.