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

Developer cookbook

Crie uma integração de ferramenta (API)

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.

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

Painel

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.

API de integrações

Crie a especificação com POST /v1/integrations ou atualize-a com PATCH /v1/integrations/{id}.

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

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.

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:

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

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" }
  }'
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:

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:

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

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

6. Teste o ciclo

Execute uma sessão de microfone 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:

{
  "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; o fluxo de eventos bruto (com tempo por entrada e deslocamentos de áudio) está em GET /v1/calls/{call_id}/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

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.").

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.

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.

Versionamento

Cada PATCH de integração cria uma nova revisão. Consulte GET /v1/integrations/{id}/versions para ver quem alterou o quê. Se quebrar o schema de uma ferramenta, você poderá reverter manualmente aplicando via PATCH um snapshot anterior.


Próximas etapas