VoltarTake Sales

Custom Tools (Ferramentas Personalizadas)

Guia completo para criar ferramentas personalizadas que conectam seu agente a qualquer API externa.

O que são Custom Tools?

Custom Tools permitem que seu agente execute chamadas HTTP para qualquer API externa durante uma conversa. Por exemplo:

  • Criar um lead no seu CRM
  • Consultar estoque de um produto
  • Agendar uma visita no seu sistema
  • Enviar dados para um webhook

Criando uma Custom Tool

No dashboard, acesse Integrações → Nova Custom Tool. Você pode criar manualmente ou colar um cURL para importar automaticamente.

Campos principais

CampoDescrição
Nome da funçãoIdentificador único (ex: criar_lead). Só aceita letras, números e _.
TítuloNome amigável exibido no dashboard (ex: "Criar Lead")
DescriçãoExplica para a IA quando e como usar a tool. Seja específico.
Método HTTPGET, POST, PUT, PATCH ou DELETE
URLEndpoint da API. Suporta interpolação com {{param}}
HeadersHeaders HTTP customizados (ex: Content-Type, X-Api-Key)
Body TemplateTemplate JSON do corpo da requisição (apenas para POST/PUT/PATCH)
ParâmetrosSchema JSON dos dados que o agente precisa coletar do usuário

Tipos de valores no Body Template

O body_template suporta 3 tipos de valores, que podem ser combinados livremente:

TipoSintaxeOrigem
HardcodedValor literalFixo no template, nunca muda
Do usuário (via LLM){{nome_do_parametro}}O agente coleta na conversa
Do browser (Client Variable){{client.nome_da_variavel}}Extraído automaticamente do navegador do visitante

Exemplo combinando os 3 tipos

{
  "source": "takesales",
  "nome": "{{nome}}",
  "email": "{{email}}",
  "interesse": "{{interesse}}",
  "user_id": "{{client.userId}}",
  "page_url": "{{client.currentPage}}"
}

Neste exemplo:

  • "source": "takesales" — hardcoded, sempre vai "takesales"
  • "nome", "email", "interesse" — coletados pelo agente na conversa (parâmetros do LLM)
  • "user_id", "page_url" — extraídos automaticamente do browser do visitante (client variables)

Valores Hardcoded

Para enviar um valor fixo que nunca muda, escreva o valor diretamente no template. Não inclua esse campo nos parâmetros — assim a IA não tenta preenchê-lo.

Exemplo: enviar origem fixa para o CRM

Body Template:

{
  "source": "chatbot",
  "campaign": "site-2024",
  "nome": "{{nome}}",
  "email": "{{email}}"
}

Parâmetros (JSON Schema):

{
  "type": "object",
  "properties": {
    "nome": {
      "type": "string",
      "description": "Nome completo do visitante"
    },
    "email": {
      "type": "string",
      "description": "Email do visitante"
    }
  },
  "required": ["nome", "email"]
}

O agente vai pedir nome e email na conversa. Os campos source e campaign vão sempre com os valores fixos.


Parâmetros do LLM (coletados na conversa)

Parâmetros definidos no JSON Schema são apresentados à IA como argumentos da função. O agente coleta esses dados naturalmente na conversa e os envia no {{placeholder}} correspondente.

Exemplo: consultar preço de produto

URL: https://api.exemplo.com/products/{{product_id}}/price

Método: GET

Parâmetros:

{
  "type": "object",
  "properties": {
    "product_id": {
      "type": "string",
      "description": "Código do produto (ex: SKU-1234)"
    }
  },
  "required": ["product_id"]
}

O agente pergunta qual produto o visitante quer e usa o código para buscar o preço. O {{product_id}} é substituído na URL automaticamente.

Tipos de parâmetros suportados

TipoExemploUso
string"nome": { "type": "string" }Textos, emails, códigos
number"valor": { "type": "number" }Valores numéricos
integer"quantidade": { "type": "integer" }Números inteiros
boolean"aceita_termos": { "type": "boolean" }Verdadeiro/falso
enum"tipo": { "type": "string", "enum": ["A", "B"] }Lista de opções fixas

Dicas para descrições de parâmetros

A descrição do parâmetro orienta a IA sobre o que pedir ao usuário. Seja específico:

{
  "type": "object",
  "properties": {
    "telefone": {
      "type": "string",
      "description": "Telefone com DDD, formato (11) 99999-9999"
    },
    "tipo_imovel": {
      "type": "string",
      "enum": ["apartamento", "casa", "terreno", "comercial"],
      "description": "Tipo de imóvel que o visitante procura"
    },
    "valor_maximo": {
      "type": "number",
      "description": "Orçamento máximo em reais (R$)"
    }
  },
  "required": ["telefone", "tipo_imovel"]
}

Client Variables (dados do browser)

Client Variables permitem capturar dados do navegador do visitante automaticamente, sem que o agente precise perguntar. Útil para enviar contexto como ID do usuário logado, página atual, dados do localStorage, etc.

Como configurar

  1. No dashboard, acesse Configurações do Agente → Client Variables
  2. Adicione variáveis com nome, fonte e chave
  3. No body template, use {{client.nome_da_variavel}}

Fontes disponíveis

FonteExemplo de chaveO que captura
localStorageuser_idlocalStorage.getItem("user_id")
sessionStoragesession_tokensessionStorage.getItem("session_token")
cookie_gaValor do cookie _ga
windowuser.profile.idwindow.user.profile.id (suporta caminhos aninhados)
querySelector#user-nametextContent do elemento
metauser-id<meta name="user-id" content="123">

Exemplo: capturar ID do usuário logado

Configuração da Client Variable:

NomeFonteChave
userIdlocalStorageapp_user_id
userEmailwindowcurrentUser.email
currentPagewindowlocation.href

Body Template:

{
  "user_id": "{{client.userId}}",
  "user_email": "{{client.userEmail}}",
  "page": "{{client.currentPage}}",
  "mensagem": "{{mensagem}}"
}

O widget extrai os valores do browser na conexão e o servidor injeta automaticamente nos args da tool com o prefixo client..


Interpolação na URL, Headers e Query Params

Os placeholders {{param}} e {{client.var}} funcionam em todos os campos da configuração do endpoint:

Na URL

https://api.exemplo.com/users/{{client.userId}}/notes

Parâmetros usados na URL são removidos automaticamente do body para evitar duplicação.

Nos Headers

X-Tenant-Id: {{client.tenantId}}
X-Request-Source: chatbot
Authorization: Bearer {{client.apiToken}}

Em Query Params (GET/DELETE)

Para métodos GET e DELETE, parâmetros que não foram usados na URL são enviados automaticamente como query string:

URL: https://api.exemplo.com/search Método: GET Parâmetros: query, category

Resultado: https://api.exemplo.com/search?query=valor&category=imoveis


Casos de uso completos

1. Criar lead no CRM (POST com dados mistos)

Cenário: O agente coleta dados do visitante e envia para o CRM. O ID do usuário logado e a origem são enviados automaticamente.

Configuração:

  • Função: criar_lead_crm
  • Descrição: "Cria um novo lead no CRM quando o visitante demonstra interesse. Colete nome, email e telefone antes de chamar."
  • Método: POST
  • URL: https://crm.exemplo.com/api/v1/leads
  • Headers: X-Api-Key: sua-chave-aqui

Parâmetros:

{
  "type": "object",
  "properties": {
    "nome": { "type": "string", "description": "Nome completo" },
    "email": { "type": "string", "description": "Email de contato" },
    "telefone": { "type": "string", "description": "Telefone com DDD" },
    "interesse": { "type": "string", "description": "O que o visitante procura" }
  },
  "required": ["nome", "email"]
}

Body Template:

{
  "name": "{{nome}}",
  "email": "{{email}}",
  "phone": "{{telefone}}",
  "notes": "{{interesse}}",
  "source": "takesales-chatbot",
  "channel": "website",
  "referred_by": "{{client.currentPage}}",
  "external_id": "{{client.userId}}"
}

Client Variables:

NomeFonteChave
currentPagewindowlocation.href
userIdlocalStorageuser_id

2. Consultar estoque (GET com parâmetro na URL)

Cenário: O visitante pergunta se um produto está disponível. O agente busca no sistema de estoque.

Configuração:

  • Função: consultar_estoque
  • Descrição: "Consulta disponibilidade de um produto pelo código SKU. Use quando o visitante perguntar sobre disponibilidade ou estoque."
  • Método: GET
  • URL: https://api.exemplo.com/inventory/{{sku}}
  • Headers: Authorization: Bearer token-fixo-aqui

Parâmetros:

{
  "type": "object",
  "properties": {
    "sku": {
      "type": "string",
      "description": "Código SKU do produto (ex: PROD-001)"
    }
  },
  "required": ["sku"]
}

Body Template: (vazio — é GET)


3. Enviar webhook com contexto completo

Cenário: Dispara um webhook para seu sistema quando o visitante quer falar com um humano.

Configuração:

  • Função: solicitar_atendimento_humano
  • Descrição: "Solicita atendimento humano quando o visitante pede para falar com uma pessoa. Colete um resumo do problema antes de chamar."
  • Método: POST
  • URL: https://hooks.exemplo.com/webhook/atendimento

Parâmetros:

{
  "type": "object",
  "properties": {
    "resumo": {
      "type": "string",
      "description": "Resumo do problema ou motivo do contato"
    },
    "urgencia": {
      "type": "string",
      "enum": ["baixa", "media", "alta"],
      "description": "Nível de urgência"
    }
  },
  "required": ["resumo"]
}

Body Template:

{
  "type": "human_handoff",
  "summary": "{{resumo}}",
  "urgency": "{{urgencia}}",
  "visitor_email": "{{client.visitorEmail}}",
  "visitor_name": "{{client.visitorName}}",
  "page_url": "{{client.pageUrl}}",
  "timestamp": "auto"
}

Client Variables:

NomeFonteChave
visitorEmaillocalStoragevisitor_email
visitorNamelocalStoragevisitor_name
pageUrlwindowlocation.href

4. Atualizar registro existente (PUT com ID na URL)

Cenário: O agente atualiza o status de um pedido no sistema do cliente.

Configuração:

  • Função: atualizar_status_pedido
  • Descrição: "Atualiza o status de um pedido. Pergunte o número do pedido e o novo status desejado."
  • Método: PUT
  • URL: https://api.exemplo.com/orders/{{order_id}}/status
  • Headers: X-Api-Key: chave-fixa

Parâmetros:

{
  "type": "object",
  "properties": {
    "order_id": {
      "type": "string",
      "description": "Número do pedido (ex: PED-12345)"
    },
    "status": {
      "type": "string",
      "enum": ["processing", "shipped", "delivered", "cancelled"],
      "description": "Novo status do pedido"
    },
    "motivo": {
      "type": "string",
      "description": "Motivo da alteração (opcional)"
    }
  },
  "required": ["order_id", "status"]
}

Body Template:

{
  "status": "{{status}}",
  "reason": "{{motivo}}",
  "updated_by": "ai-agent",
  "tenant_id": "{{client.tenantId}}"
}

Note que order_id é usado na URL e automaticamente removido do body.


5. Buscar no catálogo e exibir como carrossel (GET com query params)

Cenário: O agente busca itens na base do cliente (produtos, imóveis, cursos, veículos — qualquer catálogo) e mostra os resultados como cards no chat.

Configuração:

  • Função: buscar_catalogo
  • Descrição: "Busca itens disponíveis com filtros. Pergunte categoria, cidade e faixa de preço."
  • Método: GET
  • URL: https://api.exemplo.com/catalog

Parâmetros:

{
  "type": "object",
  "properties": {
    "category": { "type": "string", "description": "Categoria do item" },
    "city": { "type": "string", "description": "Cidade (ex: São Paulo, Curitiba)" },
    "max_price": { "type": "number", "description": "Preço máximo em reais" }
  },
  "required": ["category"]
}

Body Template: (vazio — método GET)

Para GET, os parâmetros são enviados automaticamente como query string:

https://api.exemplo.com/catalog?category=sofa&city=São+Paulo&max_price=5000

Exibir como carrossel: na aba Resposta, ligue "Exibir resultado como carrossel" e informe os caminhos (veja a seção abaixo).


6. Tool 100% automática (sem parâmetros do LLM)

Cenário: O agente envia dados do visitante para analytics sem coletar nada na conversa.

Configuração:

  • Função: registrar_interesse
  • Descrição: "Registra que o visitante demonstrou interesse. Chame automaticamente quando o visitante pedir mais informações sobre um produto."
  • Método: POST
  • URL: https://hooks.exemplo.com/analytics/interest

Parâmetros:

{
  "type": "object",
  "properties": {},
  "required": []
}

Body Template:

{
  "event": "interest_shown",
  "visitor_id": "{{client.visitorId}}",
  "page": "{{client.currentPage}}",
  "referrer": "{{client.referrer}}",
  "source": "ai-chatbot"
}

Neste caso, tudo é hardcoded ou client variable. O agente chama a tool sem precisar pedir nenhum dado ao usuário.


Exibir resultado como carrossel

Qualquer tool que devolva uma lista pode ser exibida como cards no chat (título, imagem, preço, link). Na aba Resposta, ligue Exibir resultado como carrossel e informe os caminhos:

  • Caminho da lista — a partir da raiz do resultado da tool. Para tools HTTP a raiz é { "success": true, "data": <corpo da resposta>, "status": 200 }, então quase sempre começa com data. (ex: data.items).
  • Campos — a partir de cada item da lista. Título e Link são obrigatórios; Imagem, Subtítulo, Descrição e Preço são opcionais.

Os caminhos usam ponto e colchete (results[0].photos[0].url).

O que fica salvo na tool:

{
  "display": {
    "type": "carousel",
    "items": "data.items",
    "fields": {
      "title": "name",
      "url": "link",
      "image": "photo",
      "subtitle": "city",
      "description": "summary",
      "price": "price"
    }
  }
}

O exemplo de resposta é obrigatório quando o carrossel está ligado: cole um JSON real da sua API no campo "Exemplo de resposta". Ao salvar, o backend aplica o mapeamento sobre esse JSON e recusa a tool (400) se o caminho da lista não resolver ou se nenhum item tiver título e link — o erro diz qual caminho falhou. O mesmo exemplo continua sendo incluído na descrição da tool para o agente.

O carrossel aparece no chat de texto e nas sessões de voz do widget. O resultado completo da API continua indo para o agente, que responde em texto normalmente.


Autenticação da API externa

A autenticação é configurada nas credenciais da integração "Custom" no workspace. Suporte automático:

MétodoComo configurar
Bearer tokenSalve api_key nas credenciais — é adicionado automaticamente como Authorization: Bearer ...
Header customizadoSalve api_key + api_key_header nas credenciais (ex: X-Api-Key)
No header da toolAdicione diretamente nos headers da tool: Authorization: Bearer token-fixo
No bodyInclua no body_template: "api_key": "valor-fixo"
⚠️

Evite colocar credenciais sensíveis diretamente no body template. Prefira usar as credenciais da integração (salvas de forma segura no workspace) ou os headers da tool. Valores no body template ficam visíveis para qualquer membro do workspace.


Nível de risco

Cada tool pode ter um nível de risco que controla se o agente executa automaticamente ou pede confirmação ao visitante:

NívelComportamento
autoExecuta automaticamente (padrão)
confirmExibe confirmação ao visitante antes de executar

Use confirm para ações destrutivas (deletar, cancelar) ou que envolvem dados sensíveis.

Como funciona a confirmação

Quando o agente tenta executar uma tool com nível confirm, o fluxo é:

  1. O agente pausa a execução e envia um card de confirmação inline no chat
  2. O visitante vê um card com o nome da tool, descrição e os parâmetros que serão enviados
  3. O visitante clica em Confirmar ou Cancelar
  4. Se confirmado, a tool é executada normalmente. Se cancelado, o agente recebe um aviso e pode continuar a conversa

No widget embutido, o card de confirmação já aparece automaticamente. Se você usa o SDK, precisa ouvir o evento toolConfirmation e montar sua própria UI — veja a documentação do SDK.


Debugging e Logs

Verificando a execução de tools

Para inspecionar o que aconteceu em uma chamada de tool:

  1. Acesse Conversas no dashboard e abra a sessão desejada
  2. Na timeline da conversa, localize o step da tool — ele mostra o nome da tool chamada
  3. Expanda o step para ver os parâmetros enviados (request) e a resposta recebida (response) da API externa

Erros comuns

ErroCausa provávelSolução
404 Not FoundURL incorreta ou recurso inexistenteVerifique a URL e os placeholders de interpolação
401 UnauthorizedCredenciais inválidas ou expiradasAtualize o token/API key nas credenciais da integração
TimeoutAPI externa demorando para responderA API externa deve responder em até 10 segundos; otimize o endpoint ou aumente a performance do servidor

O que acontece quando uma tool falha

Quando a chamada HTTP retorna erro ou timeout, o agente recebe uma mensagem informando a falha. A partir disso, o agente pode:

  • Informar o visitante que houve um problema e sugerir alternativas
  • Tentar uma abordagem diferente (se houver outra tool disponível)
  • Coletar os dados manualmente e prosseguir a conversa

O visitante nunca vê a resposta de erro crua da API — o agente sempre interpreta e responde de forma natural.


Salvando dados da resposta (aba Resposta)

A resposta da API não precisa morrer no turno em que foi chamada. Na aba Resposta da tool você pode:

Salvar valores em variáveis da conversa

Informe o nome da variável e o caminho na resposta (notação com ponto e colchete, com raiz no campo data):

VariávelCaminho
customer_idcustomer.id
first_itemcustomer.items[0].id

Cada variável pode ser marcada como secreta (persistida mascarada como ***) e/ou persistente (continua valendo nas próximas conversas da mesma pessoa).

Vincular a pessoa da conversa

Informe o caminho das chaves que identificam o contato — a de maior precedência vence: ID externo > CPF > telefone E.164 > e-mail — e, opcionalmente, o caminho do nome completo. Com isso a conversa passa a apontar para o registro em Pessoas.

⚠️

Só marque Identidade verificada se essa API exigir prova de identidade do visitante (token, OTP). Um endpoint que apenas ecoa uma chave digitada — por exemplo, busca por CPF informado no chat — não prova quem é o visitante, e tratá-lo como prova expõe dados de terceiros.


Resumo rápido

Hardcoded        →  "campo": "valor-fixo"         (direto no template)
LLM / Usuário    →  "campo": "{{parametro}}"       (definido no JSON Schema)
Client Variable  →  "campo": "{{client.variavel}}"  (configurado nas Client Variables)

Os três tipos podem ser combinados livremente no body_template, URL, headers e query params.