---
title: "Ferramentas de função"
description: "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

| Recurso | Onde é executado | Configuração |
| --- | --- | --- |
| [Ferramentas integradas](/pt/guides/built-in-tools) | ThunderPhone | Instruções de prompt; algumas ferramentas também exigem uma configuração do agente |
| [Conexões de apps](/pt/guides/connect-apps) | ThunderPhone e o provedor conectado | Conecte a conta e anexe ações aprovadas |
| [Conexões de API](/pt/guides/api-connections) e ferramentas de função | Sua API HTTP | Defina o endpoint e o schema ou receba chamadas de função por meio de um webhook |
| [Servidores MCP](/pt/guides/mcp-servers) | Um servidor MCP remoto | Adicione o servidor, descubra suas ferramentas e anexe-o ao agente |

---

## Schema da ferramenta

Cada ferramenta segue esta estrutura:

```json
{
  "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

| Campo | Tipo | Obrigatório | Descrição |
|-------|------|----------|-------------|
| `timeout` | número | Não | Tempo máximo de execução em segundos (padrão: `20`, máximo: `180`) |

### Definição da função

| Campo | Tipo | Obrigatório | Descrição |
|-------|------|----------|-------------|
| `name` | string | Sim | Identificador exclusivo da ferramenta |
| `description` | string | Sim | Explica à IA quando usar esta ferramenta |
| `parameters` | objeto | Sim | Schema JSON para argumentos da ferramenta |

### Configuração do endpoint

| Campo | Tipo | Obrigatório | Descrição |
|-------|------|----------|-------------|
| `url` | string | Sim | URL do endpoint da sua API |
| `method` | string | Não | Método HTTP (padrão: `POST`) |
| `headers` | objeto | Não | Cabeçalhos personalizados a incluir |

<Note>
  A configuração de `endpoint` **não** é enviada ao modelo de IA — ela é usada apenas pelo ThunderPhone para executar a chamada da ferramenta.
</Note>

---

## Dois caminhos de invocação

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

| | Ferramenta **com** `endpoint` | Ferramenta **sem** `endpoint` |
|---|---|---|
| Destino da solicitação | Diretamente para `endpoint.url` | [URL de webhook legada](/api-reference/organizations#legacy-single-url-webhook) da sua organização |
| Corpo | Formato de solicitação selecionado (argumentos sem wrapper por padrão) | Envelope `telephony.tool` / `web.tool` |
| Cabeçalhos | Seus `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature-V2` + `X-ThunderPhone-Signature` |
| Chave de assinatura | Segredo do webhook da organização | Segredo 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

```http
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](/pt/guides/verify-webhook-signatures)
- `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.

<Warning>
  A assinatura usa como chave o segredo de webhook no nível da organização de
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook).
  Se sua organização nunca configurou o webhook legado, não haverá
  segredo e as chamadas de ferramenta incluirão **somente** `X-ThunderPhone-Call-ID` —
  um manipulador que falha imediatamente diante de uma assinatura ausente as rejeitaria.
  Configure o webhook legado para obter um segredo ou inclua seu próprio
  segredo compartilhado em `endpoint.headers`.
</Warning>

### 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:

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

#### Vapi

`vapi` envia a [mensagem de servidor `tool-calls` do Vapi](https://docs.vapi.ai/tools/custom-tools)
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:

```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:

```json
{
  "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](https://docs.retellai.com/build/single-multi-prompt/custom-function):

```json
{
  "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](/pt/guides/verify-webhook-signatures).

### Resposta

Retorne uma resposta JSON com o resultado da ferramenta:

```json
{
  "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](/pt/webhooks/events)
entregues aos endpoints de webhook após a execução, esta solicitação **é**
a execução — sua resposta HTTP é o resultado da ferramenta.

```json
{
  "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.

<Note>
  Os [endpoints de webhook](/pt/webhooks/endpoints) inscritos também
  recebem uma **notificação** não bloqueante `telephony.tool` / `web.tool`
  **após** a execução de cada ferramenta (independentemente do caminho usado),
  incluindo a resposta da ferramenta — útil para trilhas de auditoria. Consulte o
  [catálogo de eventos](/pt/webhooks/events).
</Note>

---

## 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:

<CodeGroup>
```python 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}
```

```javascript 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 });
});
```
</CodeGroup>

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](/pt/guides/verify-webhook-signatures).

---

## Exemplo: fluxo completo de agendamento

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

```json
{
  "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

<AccordionGroup>
  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>
</AccordionGroup>

---

## Relacionados

<CardGroup cols={2}>
  <Card title="Ferramentas integradas" icon="wrench" href="/pt/guides/built-in-tools">
    Acione ações de chamada gerenciadas pela plataforma sem definir um endpoint.
  </Card>
  <Card title="Conexões de apps" icon="plug" href="/pt/guides/connect-apps">
    Ferramentas gerenciadas pela plataforma para HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets e Cal.com — nenhum endpoint necessário.
  </Card>
  <Card title="Servidores MCP" icon="server" href="/pt/guides/mcp-servers">
    Conecte um servidor MCP e permita que o agente chame suas ferramentas.
  </Card>
  <Card title="Conexões de API" icon="code" href="/pt/guides/api-connections">
    Integrações REST reutilizáveis que você pode conectar aos agentes.
  </Card>
  <Card title="Verificar assinaturas de webhook" icon="shield-check" href="/pt/guides/verify-webhook-signatures">
    Um único auxiliar de verificação para webhooks e chamadas de ferramentas.
  </Card>
</CardGroup>
