ThunderPhone 2.0 ya está disponible.Empieza por tu cuenta desde 2¢/min.Lee el anuncio

Function Tools

Herramientas de función

Proporciona a tus agentes de IA herramientas de función que llamen a API externas durante la conversación: obtén datos de clientes, agenda citas y actualiza registros, con parámetros tipados.

Las herramientas de función permiten que tus agentes de voz con IA invoquen API externas durante las llamadas telefónicas. Úsalas para consultar datos de clientes, verificar disponibilidad, reservar citas o realizar cualquier acción que admita tu backend.

Cómo funciona

  1. Define herramientas con un esquema (qué argumentos acepta la herramienta)
  2. Proporciona una configuración de endpoint (dónde ThunderPhone llama a tu API) o déjala fuera para recibir llamadas de herramientas en el webhook de tu organización
  3. Durante una llamada, la IA decide cuándo usar una herramienta según la conversación
  4. ThunderPhone llama a tu endpoint con los argumentos de la herramienta
  5. La respuesta de tu API se devuelve a la IA para continuar la conversación

Esquema de herramienta

Cada herramienta sigue esta estructura:

{
  "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
}

Configuración de la herramienta

CampoTipoObligatorioDescripción
timeoutnúmeroNoTiempo máximo de ejecución en segundos (predeterminado: 20, máximo: 180)

Definición de función

CampoTipoObligatorioDescripción
namecadenaIdentificador único de la herramienta
descriptioncadenaIndica a la IA cuándo usar esta herramienta
parametersobjetoEsquema JSON para los argumentos de la herramienta

Configuración del endpoint

CampoTipoObligatorioDescripción
urlcadenaURL del endpoint de tu API
methodcadenaNoMétodo HTTP (predeterminado: POST)
headersobjetoNoEncabezados personalizados que se incluirán

Dos rutas de invocación

La solicitud que recibe tu servidor depende de si la herramienta tiene un endpoint:

Herramienta con endpointHerramienta sin endpoint
Destino de la solicitudDirectamente a endpoint.urlLa URL de webhook heredada de tu organización
CuerpoArgumentos de herramienta sin envoltorioEnvoltorio telephony.tool / web.tool
EncabezadosTus endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature
Clave de firmaSecreto del webhook de la organizaciónSecreto del webhook de la organización

Ambas rutas son bloqueantes: la IA espera el resultado a mitad de la frase. El tiempo de espera predeterminado es de 20 s; configura el timeout de nivel superior de la herramienta para permitir una ejecución más larga, hasta el máximo de la plataforma de 180 s. Mantén los controladores rápidos. Se puede combinar: en una llamada cuya organización tenga una URL de webhook, las herramientas con un endpoint se llaman directamente y las demás recurren al webhook.

Llamadas directas a endpoints

Cuando la IA invoca una herramienta que tiene un endpoint, ThunderPhone envía una solicitud a tu URL:

Encabezados de la solicitud

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-key

Los encabezados personalizados de tu endpoint.headers siempre se incluyen textualmente, además de dos encabezados con espacio de nombres de ThunderPhone:

  • X-ThunderPhone-Signature — HMAC-SHA256 de los bytes exactos del cuerpo de la solicitud, con clave de tu secreto de webhook de la organización
  • X-ThunderPhone-Call-ID — El ID de la llamada actual

Content-Type: application/json se establece a menos que tus endpoint.headers lo reemplacen; un Content-Type personalizado tiene prioridad.

Cuerpo de la solicitud

Para POST / PUT / PATCH, el cuerpo contiene solo los argumentos de la herramienta (sin envoltorio), serializados canónicamente (claves ordenadas, separadores compactos):

{"date":"2025-01-02","service":"consultation"}

Para GET / DELETE, los argumentos se envían como parámetros de consulta y el cuerpo está vacío; la firma se calcula entonces sobre la cadena de bytes vacía. Consulta Verificar firmas de webhook.

Respuesta

Devuelve una respuesta JSON con el resultado de la herramienta:

{
  "available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
  "timezone": "America/Los_Angeles"
}

La respuesta se formatea y se proporciona a la IA para continuar la conversación. Las respuestas que no son JSON se envuelven como {"data": "<text>"}; los tiempos de espera y los errores de conexión se reportan a la IA como errores, para que el agente pueda disculparse y continuar en lugar de bloquearse.

Despacho en modo webhook

Las herramientas sin un endpoint se envían a la URL de webhook heredada de tu organización como una solicitud firmada telephony.tool (llamadas telefónicas) o web.tool (llamadas web). A diferencia de las notificaciones de auditoría entregadas a endpoints de webhook después de la ejecución, esta solicitud es la ejecución; tu respuesta HTTP es el resultado de la herramienta.

{
  "type": "telephony.tool",
  "data": {
    "call_id": 987654321,
    "tool_name": "search_appointments",
    "arguments": { "date": "2026-04-21" },
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  }
}

web.tool incluye origin_domain en lugar de from_number / to_number. Responde con el resultado de la herramienta como JSON; el mismo contrato de respuesta que para las llamadas directas a endpoints. La solicitud se firma con el secreto de webhook de la organización sobre el cuerpo sin procesar, como cualquier otro webhook.


Verificación de firmas

Las llamadas directas a herramientas se firman de la misma manera que los webhooks:

  • HMAC-SHA256 sobre los bytes exactos del cuerpo de la solicitud (el JSON canónico: claves ordenadas, sin espacios adicionales)
  • Con tu secreto de webhook de la organización como clave
  • Las herramientas GET / DELETE firman la cadena de bytes vacía
Python
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}
Node.js
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 });
});

Las recetas completas, incluido el caso de cuerpo vacío y la advertencia sobre no tener secreto, están en Verificar firmas de webhooks.


Ejemplo: flujo de reservas completo

Aquí tienes un conjunto de herramientas para un sistema completo de reservas de citas:

{
  "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" }
      }
    }
  ]
}

Prácticas recomendadas

Escribe descripciones claras

El campo description ayuda a la IA a entender cuándo usar la herramienta. Especifica qué hace y cuándo corresponde usarla.

Maneja los errores correctamente

Devuelve mensajes de error que la IA pueda entender: {"error": "No slots available for that date"} en lugar de errores 500 genéricos.

Mantén las respuestas concisas

Devuelve solo lo que la IA necesita para continuar la conversación. Las cargas útiles grandes ralentizan los tiempos de respuesta.

Usa los campos obligatorios con criterio

Marca los campos como required solo cuando sea realmente necesario. La IA le pedirá al usuario la información obligatoria antes de llamar a la herramienta.


Contenido relacionado