> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Ferramentas de função

> Permita que seus agentes de IA chamem APIs externas durante conversas

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 esquema (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

<Note>
  As ferramentas de função são a opção para usar sua própria API. O ThunderPhone também
  oferece ferramentas gerenciadas pela plataforma que não exigem endpoint:
  [conexões de aplicativos](/pt/guides/connect-apps) (HubSpot, Salesforce, Slack,
  Google Calendar, Google Sheets, Cal.com),
  [conexões de API](/pt/guides/api-connections) e
  [servidores MCP](/pt/guides/mcp-servers).
</Note>

***

## Esquema da ferramenta

Cada ferramenta segue esta estrutura:

```json theme={null}
{
  "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"
    }
  }
}
```

### 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`  | object | Sim         | Esquema JSON para os 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` | object | 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`                                                                      |
| --------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Para onde a solicitação vai | Diretamente para `endpoint.url`                                                 | [URL de webhook legada](/api-reference/organizations#legacy-single-url-webhook) da sua organização |
| Corpo                       | **Apenas argumentos da ferramenta**                                             | Envelope `telephony.tool` / `web.tool`                                                             |
| Cabeçalhos                  | Seus `endpoint.headers` + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature`                                                        |
| Chave de assinatura         | Segredo do webhook da organização                                               | Segredo do webhook da organização                                                                  |

Os dois caminhos são **bloqueantes** — a IA aguarda o resultado no
meio da frase — com um tempo limite de **20 s**. Mantenha os handlers rápidos. Uma combinação é válida:
em uma chamada cuja organização tenha uma URL de webhook, as ferramentas com um `endpoint` são
chamadas diretamente, e as demais usam o webhook como alternativa.

## 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 theme={null}
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
```

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

* `X-ThunderPhone-Signature` — HMAC-SHA256 dos bytes exatos do corpo da
  solicitação, com chave definida pelo seu **segredo de webhook da organização**
* `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 há
  segredo e as chamadas de ferramenta incluem **apenas** `X-ThunderPhone-Call-ID` —
  um manipulador que falha imediatamente quando a assinatura está ausente as rejeitaria.
  Configure o webhook legado para obter um segredo ou inclua seu próprio
  segredo compartilhado em `endpoint.headers`.
</Warning>

### Corpo da solicitação

Para `POST` / `PUT` / `PATCH`, o corpo contém **apenas** os argumentos da
ferramenta (sem invólucro), serializados canonicamente (chaves ordenadas, separadores
compactos):

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

Para `GET` / `DELETE`, os argumentos são enviados como **parâmetros de consulta**
e o corpo fica vazio — a assinatura é então calculada sobre a string de
bytes vazia. Consulte
[Verificar assinaturas de webhook](/pt/guides/verify-webhook-signatures).

### Resposta

Retorne uma resposta JSON com o resultado da ferramenta:

```json theme={null}
{
  "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 adiante em vez de travar.

## 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 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 theme={null}
{
  "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 como JSON — o mesmo contrato de
resposta das chamadas diretas de endpoint. A solicitação é assinada com o segredo de
webhook da organização sobre o corpo bruto, como todos os outros webhooks.

<Note>
  Os [endpoints de webhook](/pt/webhooks/endpoints) assinados também
  recebem uma **notificação** `telephony.tool` / `web.tool` sem bloqueio
  **após** a execução de cada ferramenta (independentemente do caminho que a executou), 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:

* HMAC-SHA256 sobre os bytes exatos do corpo da solicitação (o JSON canônico —
  chaves ordenadas, sem espaços em branco extras)
* Com chave baseada no segredo de webhook da sua organização
* Ferramentas `GET` / `DELETE` assinam a string de bytes vazia

<CodeGroup>
  ```python Python theme={null}
  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}
  ```

  ```javascript Node.js theme={null}
  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 });
  });
  ```
</CodeGroup>

Receitas completas — incluindo o caso de corpo vazio e a ressalva sobre não haver segredo —
estão em [Verificar assinaturas de webhook](/pt/guides/verify-webhook-signatures).

***

## Exemplo: fluxo completo de agendamento

Veja um conjunto de ferramentas para um sistema completo de agendamento de consultas:

```json theme={null}
{
  "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="Lide com erros de forma adequada">
    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 reduzem a velocidade de resposta.
  </Accordion>

  <Accordion title="Use campos obrigatórios com critério">
    Marque campos como `required` apenas quando for realmente necessário. A IA pedirá ao usuário as informações obrigatórias antes de chamar a ferramenta.
  </Accordion>
</AccordionGroup>

***

## Relacionados

<CardGroup cols={2}>
  <Card title="Conexões de aplicativos" 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 a agentes.
  </Card>

  <Card title="Verifique assinaturas de webhook" icon="shield-check" href="/pt/guides/verify-webhook-signatures">
    Um auxiliar de verificação para webhooks e chamadas de ferramentas.
  </Card>
</CardGroup>
