ThunderPhone 2.0 já está no ar.Contrate online, a partir de 2¢/min.Leia o anúncio

Function Tools

Ferramentas de função

Ofereça aos seus agentes de IA ferramentas de função que chamam APIs externas durante a conversa — buscam dados de clientes, agendam compromissos, atualizam registros — com parâmetros tipados.

As ferramentas de função permitem que seus agentes de IA invoquem APIs externas durante chamadas telefônicas. Use-as para consultar dados de clientes, verificar disponibilidade, agendar compromissos ou executar qualquer ação compatível com seu backend.

Como funciona

  1. Defina ferramentas com um schema (quais argumentos a ferramenta aceita)
  2. Forneça uma configuração de endpoint (onde o ThunderPhone chama sua API) — ou omita-a para receber chamadas de ferramenta no webhook da sua organização
  3. Durante uma chamada, a IA decide quando usar uma ferramenta com base na conversa
  4. O ThunderPhone chama seu endpoint com os argumentos da ferramenta
  5. A resposta da sua API é enviada de volta à IA para continuar a conversa
RecursoOnde é executadoConfiguração
Ferramentas integradasThunderPhoneInstruções de prompt; algumas ferramentas também exigem uma configuração do agente
Conexões de appsThunderPhone e o provedor conectadoConecte a conta e anexe ações aprovadas
Conexões de API e ferramentas de funçãoSua API HTTPDefina o endpoint e o schema ou receba chamadas de função por meio de um webhook
Servidores MCPUm servidor MCP remotoAdicione o servidor, descubra suas ferramentas e anexe-o ao agente

Schema da ferramenta

Cada ferramenta segue esta estrutura:

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

Configuração da ferramenta

CampoTipoObrigatórioDescrição
timeoutnúmeroNãoTempo máximo de execução em segundos (padrão: 20, máximo: 180)

Definição da função

CampoTipoObrigatórioDescrição
namestringSimIdentificador exclusivo da ferramenta
descriptionstringSimExplica à IA quando usar esta ferramenta
parametersobjetoSimSchema JSON para argumentos da ferramenta

Configuração do endpoint

CampoTipoObrigatórioDescrição
urlstringSimURL do endpoint da sua API
methodstringNãoMétodo HTTP (padrão: POST)
headersobjetoNãoCabeçalhos personalizados a incluir

Dois caminhos de invocação

A solicitação que seu servidor recebe depende de a ferramenta ter um endpoint:

Ferramenta com endpointFerramenta sem endpoint
Destino da solicitaçãoDiretamente para endpoint.urlURL de webhook legada da sua organização
CorpoFormato de solicitação selecionado (argumentos sem wrapper por padrão)Envelope telephony.tool / web.tool
CabeçalhosSeus endpoint.headers + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature-V2 + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature-V2 + X-ThunderPhone-Signature
Chave de assinaturaSegredo do webhook da organizaçãoSegredo do webhook da organização

Ambos os caminhos são bloqueantes — a IA aguarda o resultado em meio à frase. O tempo limite padrão é de 20 s; defina o timeout de nível superior da ferramenta para permitir uma execução mais longa, até o máximo da plataforma de 180 s. Mantenha os handlers rápidos. Uma combinação é aceitável: em uma chamada cuja organização tenha uma URL de webhook, as ferramentas com um endpoint são chamadas diretamente, e as demais recorrem ao webhook.

Chamadas diretas de endpoint

Quando a IA invoca uma ferramenta que tem um endpoint, o ThunderPhone envia uma solicitação para sua URL:

Cabeçalhos da solicitação

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

Cabeçalhos personalizados de endpoint.headers são sempre incluídos literalmente, além destes cabeçalhos no namespace do ThunderPhone:

  • X-ThunderPhone-Signature-V2 — HMAC-SHA256 com carimbo de data e hora sobre o método, caminho, consulta e corpo, com chave no seu segredo de webhook da organização. Verifique este e rejeite solicitações com mais de 5 minutos; consulte Verificar assinaturas de webhook
  • X-ThunderPhone-Signature — HMAC-SHA256 legado dos bytes exatos do corpo da solicitação, mesma chave, ainda enviado para verificadores existentes
  • X-ThunderPhone-Call-ID — O ID da chamada atual

Content-Type: application/json é definido, a menos que endpoint.headers o substitua — um Content-Type personalizado prevalece.

Formato da solicitação

Cada conexão de API tem uma configuração request_format. Escolha vapi ou retell quando uma ferramenta importada precisar continuar chamando um endpoint criado para essa plataforma. Conexões novas e existentes usam standard por padrão.

Para POST / PUT / PATCH, o ThunderPhone serializa o envelope selecionado canonicamente (chaves ordenadas, separadores compactos). Ambas as assinaturas abrangem exatamente esses bytes.

Padrão

standard envia apenas os argumentos da ferramenta, sem um invólucro. Este é o padrão e preserva o corpo da solicitação original do ThunderPhone byte por byte:

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

Vapi

vapi envia a mensagem de servidor tool-calls do Vapi no formato documentado pelo Vapi. O call.id é o ID da chamada do ThunderPhone. O id da chamada de ferramenta é exclusivo da invocação e é reutilizado para associar o resultado do endpoint. A chamada aparece em toolCallList e toolWithToolCallList, com function.arguments como um objeto 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" }
          }
        }
      }
    ]
  }
}

Campos exclusivos do Vapi, como assistant, artifact e o objeto call completo, não são enviados.

Retorne o envelope de resposta do Vapi com o ID correspondente da chamada de ferramenta:

{
  "results": [
    {
      "toolCallId": "call_00112233445566778899aabbccddeeff",
      "result": "{\"available_slots\":[\"9:00 AM\",\"2:00 PM\"]}"
    }
  ]
}

O ThunderPhone fornece à IA a string result sem o envelope. Ele também aceita um valor JSON para compatibilidade com endpoints que já retornam um. Um error no lugar de result é retornado à IA como um erro de ferramenta. Se o endpoint retornar um envelope do Vapi malformado ou incompatível, o ThunderPhone registra um aviso e usa a análise padrão de respostas em vez de falhar a chamada.

Retell

retell envia a solicitação documentada para uma função personalizada do Retell:

{
  "name": "search_appointments",
  "call": { "call_id": "987654321" },
  "args": { "date": "2025-01-02", "service": "consultation" }
}

O objeto call inclui apenas call_id. O ThunderPhone não inclui campos específicos do Retell que não pode fornecer de maneira confiável no envio, como agent_id, transcript, transcript_object, metadata ou variáveis dinâmicas. O Retell aceita qualquer corpo de resposta; o ThunderPhone o encaminha usando o tratamento padrão de respostas.

Para GET / DELETE, os argumentos são enviados como parâmetros de consulta e o corpo fica vazio, independentemente de request_format. A assinatura V2 abrange a string de consulta conforme enviada; a assinatura legada é calculada sobre a string de bytes vazios. Consulte Verificar assinaturas de webhook.

Resposta

Retorne uma resposta JSON com o resultado da ferramenta:

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

A resposta é formatada e fornecida à IA para continuar a conversa. Respostas que não são JSON são encapsuladas como {"data": "<text>"}; tempos limite e falhas de conexão são informados à IA como erros, para que o agente possa pedir desculpas e seguir em frente em vez de ficar bloqueado.

Despacho no modo webhook

Ferramentas sem um endpoint são despachadas para a URL de webhook legado da sua organização como uma solicitação assinada telephony.tool (chamadas telefônicas) ou web.tool (chamadas pela web). Diferentemente das notificações de auditoria entregues aos endpoints de webhook após a execução, esta solicitação é a execução — sua resposta HTTP é o resultado da ferramenta.

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

web.tool inclui origin_domain em vez de from_number / to_number. Responda com o resultado da ferramenta em JSON — o mesmo contrato de resposta das chamadas diretas ao endpoint. A solicitação é assinada com o segredo de webhook da organização, usando ambos os cabeçalhos de assinatura, como qualquer outro webhook.


Verificação de assinatura

As chamadas diretas de ferramentas são assinadas da mesma forma que os webhooks, usando o segredo de webhook da sua organização:

  • X-ThunderPhone-Signature-V2 assina o carimbo de data e hora, o método, o caminho e a consulta conforme enviados, além dos bytes exatos do corpo. Rejeite solicitações cujo carimbo de data e hora esteja a mais de 5 minutos do seu relógio.
  • X-ThunderPhone-Signature (legado) assina apenas os bytes do corpo, ou a string de bytes vazia para GET / DELETE. Ele ainda é enviado, sem alterações.

Os auxiliares do SDK verificam o cabeçalho V2, incluindo a janela de 5 minutos:

Python
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}
Node.js
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 });
});

As receitas completas — a string assinada, um exemplo detalhado, código sem o SDK, o caso GET / DELETE e a observação sobre a ausência de segredo — estão em Verificar assinaturas de webhook.


Exemplo: fluxo completo de agendamento

Este é um conjunto de ferramentas para um sistema completo de agendamento:

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

Boas práticas

Escreva descrições claras

O campo description ajuda a IA a entender quando usar a ferramenta. Seja específico sobre o que ela faz e quando é apropriada.

Trate erros adequadamente

Retorne mensagens de erro que a IA possa entender: {"error": "No slots available for that date"} em vez de erros 500 genéricos.

Mantenha as respostas concisas

Retorne apenas o que a IA precisa para continuar a conversa. Cargas úteis grandes tornam os tempos de resposta mais lentos.

Use campos obrigatórios com critério

Marque campos como required apenas quando for realmente necessário. A IA solicitará a informação obrigatória ao usuário antes de chamar a ferramenta.


Relacionados