---
title: "Crie uma integração de ferramenta (API)"
description: "Permita que seu agente chame suas APIs durante a conversa — pesquise um banco de dados, crie um ticket, consulte um pedido."
---

Uma **integração de ferramenta** é um endpoint HTTP reutilizável que um agente pode
invocar durante uma chamada. Você fornece ao ThunderPhone uma descrição de esquema JSON
da ferramenta junto com uma URL de endpoint; o agente decide quando chamá-la
com base na conversa, e o ThunderPhone faz a solicitação HTTP de saída
a partir de seus servidores e retorna a resposta ao agente.

<Note>
  O painel cobre a maioria das necessidades de ferramentas sem esta API: **Conexões
  → Aplicativos** conecta Slack, HubSpot, Salesforce, Google Calendar,
  Google Sheets e Cal.com com poucos cliques de OAuth; **Conexões →
  APIs** transforma qualquer API HTTP em uma ação do agente (cole um comando cURL
  e um assistente de IA cria um rascunho da ferramenta, com uma Solicitação de teste integrada); e
  **Conexões → MCP** adiciona servidores MCP. Consulte
  [Conexões](/pt/guides/concepts). Este guia aborda a API
  bruta por trás da interface de APIs.
</Note>

Este guia mostra como criar uma ferramenta de consulta de previsão do tempo de ponta a ponta.

## Anatomia de uma ferramenta

Duas partes:

1. **O esquema** — uma definição de função no estilo OpenAI
   (`{type: "function", function: {name, description, parameters}}`)
   que informa ao LLM o que a ferramenta faz e quais argumentos ela aceita.
2. **O endpoint** — a URL que os servidores do ThunderPhone chamam quando o
   LLM decide usar a ferramenta. A solicitação é um POST JSON com os
   argumentos escolhidos pelo LLM como corpo.

## 1. Escolha um editor

<CardGroup cols={2}>
  <Card title="Painel" icon="window-maximize">
    Abra **Conexões → APIs**, crie ou edite a conexão de API,
    alterne o editor de parâmetros para **JSON** e adicione o formato ali.
  </Card>
  <Card title="API de integrações" icon="plug">
    Crie a especificação com `POST /v1/integrations` ou atualize-a com
    `PATCH /v1/integrations/{id}`.
  </Card>
</CardGroup>

Ambos os caminhos criam uma integração salva. Anexe essa integração ao
agente depois de salvá-la. A API de Agentes não tem um campo inline `tools`
gravável. Este guia usa o caminho da API de integrações.

## 2. Crie a integração

```bash
curl -X POST https://api.thunderphone.com/v1/integrations \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Weather API",
    "spec": {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Return the current weather for a zip code.",
        "parameters": {
          "type": "object",
          "properties": {
            "zip": { "type": "string", "description": "5-digit US ZIP code" }
          },
          "required": ["zip"]
        }
      }
    },
    "endpoint_url":    "https://api.example.com/weather",
    "endpoint_method": "GET",
    "headers": [
      { "key": "X-Api-Key", "value": "your-provider-key" }
    ]
  }'
```

Salve o `id` retornado (um UUID). Os valores dos cabeçalhos são somente para escrita: as respostas listam apenas os nomes dos cabeçalhos, e um `PATCH` posterior pode enviar um cabeçalho sem um `value` para manter o valor armazenado.

<Tip>
  Dedique atenção real à `description` da ferramenta e de cada
  parâmetro. O LLM usa essas strings em tempo de execução para decidir
  se e como chamar a ferramenta. Descrições vagas → chamadas de ferramenta vagas.
</Tip>

### Declare `format: "email"` nos parâmetros de endereço

Um parâmetro que recebe um endereço de e-mail deve indicá-lo em seu
schema:

```json
"email": { "type": "string", "format": "email", "description": "The caller's email address" }
```

`format` é mais do que uma dica. Para um schema de e-mail resolvido, antes de chamar
seu endpoint, o ThunderPhone remove espaços nas extremidades do valor, converte o
domínio para minúsculas, transforma as palavras em inglês isoladas `at`, `dot`,
`underscore`, `dash` e `hyphen` em seus caracteres e remove espaços em branco
diretamente ao redor de `@`, `.`, `_` e `-`. As palavras têm o mesmo significado,
independentemente de a transcrição já conter um `@` literal:
`"john dot smith at gmail dot com"` torna-se
`john.smith@gmail.com`.

Qualquer outro espaço em branco interno é rejeitado, em vez de ser unido
silenciosamente. As palavras faladas para separadores são exclusivas do inglês;
formas espaçadas em outros idiomas ou não reconhecidas falham de modo seguro.
Domínios internacionalizados válidos e partes locais SMTPUTF8 são aceitos. A
entrada em punycode permanece em punycode, e a entrada de domínio Unicode permanece
em Unicode após a normalização do analisador, para que sua API receba a representação
convencional fornecida por quem liga. Se o valor final for inválido, a ferramenta
**não será chamada**. O agente recebe
`invalid_email_argument`, instruindo-o
a confirmar a grafia com quem liga e reenviar o endereço literal.

Um e-mail opcional omitido não é alterado. `null`, uma string vazia ou uma
string composta apenas por espaços em branco também não são alterados quando a
propriedade é opcional ou anulável; os mesmos valores são rejeitados para um
e-mail obrigatório e não anulável.

Referências locais de schema, como `#/$defs/email` e
`#/definitions/email`, além de `anyOf`, `oneOf` e `allOf`, são inspecionadas
com limites de ciclo e profundidade. Um `$ref` não local ou não resolvível é um
limite de aplicação conhecido e é transmitido sem alterações, assim como uma chamada
cujo snapshot da ferramenta não tenha um schema utilizável. Mantenha os schemas de
e-mail locais quando precisar que a validação seja aplicada.

Parâmetros sem um formato de e-mail aplicado são transmitidos exatamente
como o modelo os produziu.

Os formatos compatíveis são `date-time`, `time`, `date`, `duration`,
`email`, `hostname`, `ipv4`, `ipv6` e `uuid`; atualmente, apenas `email` é
normalizado e aplicado.

## 3. Teste o endpoint em sandbox

Antes de vincular a integração a um agente, envie uma solicitação assinada
dos servidores do ThunderPhone para confirmar a conectividade:

```bash
curl -X POST https://api.thunderphone.com/v1/integrations/test-request \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url":    "https://api.example.com/weather?zip=94110",
    "method": "GET",
    "headers": { "X-Api-Key": "your-provider-key" }
  }'
```

```json Response
{
  "ok": true,
  "status": 200,
  "elapsed_ms": 187,
  "response_headers": { "content-type": "application/json" },
  "response_preview": "{\"temperature_f\": 64, ...}"
}
```

Esse teste também reforça as proteções SSRF do ThunderPhone — solicitações para
localhost ou intervalos de IP privados retornam `400 code=url_not_allowed`.

## 4. Vincule a integração a um agente

Anexe por meio de `integration_ids` ao criar ou atualizar um agente:

```bash
curl -X PATCH https://api.thunderphone.com/v1/agents/12 \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_ids": ["f9b5a1a4-..."]
  }'
```

Você pode vincular várias integrações a um agente. O prompt do agente pode
referenciá-las pelo nome — "use `get_weather` quando quem liga perguntar
sobre as condições" — ou pode descobri-las implicitamente a partir das
descrições do schema.

## 5. Implemente o endpoint

Quando o agente invoca a ferramenta, o ThunderPhone envia uma solicitação POST assinada para
seu `endpoint_url`:

```
POST /weather HTTP/1.1
Host: api.example.com
X-Api-Key: your-provider-key
X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<HMAC-SHA256 hex>
X-ThunderPhone-Signature: <HMAC-SHA256 hex>
X-ThunderPhone-Call-ID: 987654321
Content-Type: application/json

{"zip": "94110"}
```

Seu servidor responde com JSON, que é devolvido ao LLM:

```json
{"temperature_f": 64, "condition": "Partly cloudy", "wind_mph": 8}
```

O LLM processa essa resposta e fornece um resumo em linguagem natural para
quem liga.

<Warning>
  A assinatura é calculada sobre o corpo bruto da solicitação usando o mesmo
  `secret` do endpoint de webhook. **Verifique-a** — os endpoints de ferramentas
  ficam expostos à internet e estão sujeitos aos mesmos riscos de falsificação que
  os webhooks. Consulte
  [Verificar assinaturas de webhook](/pt/guides/verify-webhook-signatures).
</Warning>

## 6. Teste o ciclo

Execute uma [sessão de microfone](/api-reference/mic-sessions) com o agente
e faça a pergunta que sua ferramenta processa ("Como está o tempo em
94110?"). A transcrição da chamada mostra o ciclo completo:

```json
{
  "call_id": 987654321,
  "transcripts": [
    { "role": "user",
      "content": "What's the weather in 94110?" },
    { "role": "tool_call",
      "content": "{\"tool_call\": \"get_weather\", \"arguments\": {\"zip\": \"94110\"}}" },
    { "role": "tool_response",
      "content": "{\"tool_name\": \"get_weather\", \"response\": {\"temperature_f\": 64, \"condition\": \"Partly cloudy\"}}" },
    { "role": "agent",
      "content": "It's 64 degrees and partly cloudy." }
  ]
}
```

Você pode obter isso por meio de
[`GET /v1/calls/{call_id}/transcript`](/api-reference/calls#get-transcript);
o fluxo de eventos bruto (com tempo por entrada e deslocamentos de áudio) está em
[`GET /v1/calls/{call_id}/history`](/api-reference/calls#get-history).

Nas interfaces de listagem de chamadas e análises, o ThunderPhone agora informa chamadas de teste separadamente do tráfego real. Os testes e as simulações do Browser Talk podem reutilizar um número de telefone real e parecer recebidos, mas não contam para os totais de chamadas de produção, avaliações ou métricas de problemas.

## Problemas comuns

<AccordionGroup>
  <Accordion title="O agente nunca chama a ferramenta">
    O LLM decide com base na descrição da ferramenta. Se a pergunta de quem liga
    não corresponder à descrição, o modelo não invocará a ferramenta. Torne a
    descrição mais específica (adicione sinônimos e formulações comuns) ou
    mencione-a explicitamente no prompt do agente ("Quando quem liga perguntar
    sobre o tempo, use `get_weather`.").
  </Accordion>

  <Accordion title="A ferramenta retorna dados demais">
    Respostas com mais de 6 kB são truncadas na visualização da transcrição. Retorne
    apenas os campos de que o LLM precisa — não a linha inteira.
  </Accordion>

  <Accordion title="Tempos limite">
    Os endpoints de ferramentas têm um tempo limite padrão de 10 segundos. Se precisar de mais
    tempo, processe de forma assíncrona: retorne `{"status": "pending", "request_id": "..."}`
    e apresente o resultado por meio de uma chamada de ferramenta separada.
  </Accordion>

  <Accordion title="Versionamento">
    Cada `PATCH` de integração cria uma nova revisão. Consulte
    [`GET /v1/integrations/{id}/versions`](/api-reference/integrations#version-history)
    para ver quem alterou o quê. Se quebrar o schema de uma ferramenta, você poderá
    reverter manualmente aplicando via PATCH um snapshot anterior.
  </Accordion>
</AccordionGroup>

---

## Próximas etapas

<CardGroup cols={2}>
  <Card title="Referência de integrações" icon="plug" href="/api-reference/integrations">
    CRUD, transferência, histórico de versões.
  </Card>
  <Card title="Especificação de ferramentas de função" icon="screwdriver-wrench" href="/pt/tools/overview">
    Gramática completa do esquema JSON e o contrato de endpoint assinado.
  </Card>
  <Card title="Verificar assinaturas" icon="shield-check" href="/pt/guides/verify-webhook-signatures">
    Aplique o padrão de assinatura de webhook aos endpoints de ferramentas.
  </Card>
  <Card title="API de transcrição + histórico" icon="phone" href="/api-reference/calls">
    Inspecione o ciclo completo de ida e volta de uma chamada de ferramenta.
  </Card>
</CardGroup>
