--- title: Chatbot com IA para loja virtual: responde com as suas políticas e diz onde está o pedido description: Como criar um chatbot com IA para loja virtual com a API da Zavu: responde com as políticas de frete e trocas, consulta pedidos e passa para uma pessoa. date: 2026-10-19 author: Zavu Team locale: pt source: https://www.zavu.dev/pt/blog/chatbot-ia-tienda-online tags: AI Agents, E-commerce, Nuvemshop, WhatsApp, Telegram, Tutorial, API v2 --- # Chatbot com IA para loja virtual: responde com as suas políticas e diz onde está o pedido ## TL;DR - **As respostas saem das suas políticas.** O agente busca numa base de conhecimento com os seus documentos de frete, trocas e perguntas frequentes antes de responder. - **O status do pedido vem da sua loja.** Uma tool `get_order_status` chama o seu endpoint HTTPS, que verifica a assinatura e devolve o status real. - **Você testa sem mandar mensagem para clientes.** `POST /v2/agents/{agentId}/test` devolve a resposta e a tool que o modelo escolheu; com o provider `zavu` o teste é cobrado como uma resposta real. - **Comece no Telegram e troque de canal depois.** O Telegram conecta com uma chamada à API; WhatsApp e Instagram, em **Canais** no dashboard, com o mesmo agente. - **Responder pela caixa de entrada não pausa o agente.** Só o passo `transfer` de um fluxo pausa, até alguém da sua equipe responder. Uma loja virtual recebe quase sempre as mesmas cinco perguntas: cadê meu pedido, quanto é o frete, posso trocar, tem em outro tamanho, quantos dias para chegar. Um chatbot com IA para loja virtual vale a pena quando responde isso com as suas políticas reais e os seus pedidos reais, e não com o que o modelo imagina. Este tutorial monta isso sobre a API da Zavu, de ponta a ponta, com HTTP simples. Funciona igual se você vende na Nuvemshop, na Shopify ou no seu próprio site. No final você tem: - Um canal de chat conectado (Telegram para começar, WhatsApp ou Instagram quando for para produção). - Um agente com IA que responde a partir de uma base de conhecimento com a sua política de frete, de trocas e devoluções e as perguntas frequentes. - Uma tool `get_order_status`: o agente chama o seu endpoint, você verifica a assinatura e responde com o status do pedido direto da sua loja. - Um jeito de testar tudo sem mandar mensagem para nenhum cliente. - Uma palavra-chave que passa a conversa para uma pessoa, e o agente quieto até essa pessoa responder. Se você prefere fazer pelo painel, [o passo a passo do agente de suporte](/pt/blog/agente-de-soporte-con-ia) monta a versão do Telegram sem código. Este post é a versão pela API, com os seus pedidos dentro do loop. ## O que você precisa - **Uma conta na Zavu e uma API key.** Todas as chamadas abaixo enviam `Authorization: Bearer $ZAVUDEV_API_KEY`. - **Um canal onde os seus clientes escrevem.** Cada um tem um custo diferente para colocar no ar: - **Telegram**: um token de bot do @BotFather. Uma chamada à API, sem revisão, sem conta na Meta. O jeito mais rápido de ter algo real para testar. - **WhatsApp**: uma conta do WhatsApp Business pelo cadastro da Meta, conectada em **Canais** no painel. É o canal com mais atrito para conectar, e no Brasil quase sempre é o que o seu cliente realmente usa. - **Instagram**: também passa pela Meta, em **Canais** no painel. - **Um endpoint HTTPS do seu lado** que saiba buscar um pedido. Ele precisa ser público: a Zavu recusa uma tool cuja URL não é um endereço HTTPS público. - **As suas políticas em texto.** Frete, trocas e devoluções, formas de pagamento, o que você responde toda semana no direct. Os SDKs (`@zavudev/sdk`, `zavudev`) chamam a API v1. A API v2 é chamada por HTTP, então os exemplos usam `curl` e `fetch`. Duas peças desta montagem ainda não têm endpoint na v2, a base de conhecimento e as tools, e ficam na v1 em `/v1/agents/{agentId}/...`, com a mesma key e o mesmo id de agente. O [guia de migração](https://docs.zavu.dev/api-v2/migrate-from-v1) lista o que continua na v1. Cada passo diz qual versão usa. ## 1. Conectar um canal (v2) Comece pelo Telegram. Crie um bot com o @BotFather, copie o token e conecte: ```bash curl -X POST https://api.zavu.dev/v2/channels \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{"type": "telegram", "botToken": "123456789:AA..."}' ``` O `201` lista as entradas do endereço que você conectou. O endereço de um bot do Telegram é `@nomedobot`: ```json { "items": [ { "address": "@loja_aurora_bot", "type": "telegram", "active": true, "v1SenderId": "kd7..." } ] } ``` Se o Telegram recusar o token, nada é criado e você recebe `400 invalid_bot_token`, com as palavras do Telegram em `details.telegramSaid`. Copie o token de novo no @BotFather. Confira `active`. Uma conexão que no seu plano custa dinheiro nasce desligada; você liga com `POST /v2/channels/{address}/{type}/activate`, e a resposta diz quanto cobrou em `chargedCents` e `monthlyCents`. Detalhes em [Endereços e canais](https://docs.zavu.dev/api-v2/addresses). WhatsApp e Instagram não se conectam por este endpoint. Eles se conectam em **Canais** no painel; depois de conectados aparecem em `GET /v2/channels` e o resto do tutorial funciona igual, com o número (por exemplo `+5511987654321`) ou o `@usuario` como endereço. ## 2. Criar o agente (v2) ```bash curl -X POST https://api.zavu.dev/v2/agents \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Assistente Loja Aurora", "provider": "zavu", "model": "openai/gpt-4o-mini", "systemPrompt": "Você atende clientes da Loja Aurora, uma loja virtual brasileira. Responda só com a base de conhecimento e a tool get_order_status. Se a resposta não estiver lá, diga que não sabe e ofereça falar com uma pessoa. Para consultar um pedido, peça o número do pedido e o e-mail da compra. Nunca invente prazo de entrega. Respostas curtas: isto é um chat." }' ``` `name`, `provider`, `model` e `systemPrompt` são obrigatórios, e a v2 aponta todos os que faltam num único `400`. `provider` é `openai`, `anthropic`, `google`, `mistral` ou `zavu`. `zavu` é o provedor gerenciado: você não precisa de API key própria e cada resposta é cobrada do seu saldo na Zavu por token. Com qualquer outro provedor você envia `apiKey` e os tokens são cobrados na sua conta desse provedor. Com `zavu`, `model` é escrito como `provedor/modelo`, por exemplo `openai/gpt-4o-mini`; o seletor de modelos do painel lista o catálogo em vigor. Duas coisas da resposta importam. O agente é criado **desativado**, e o `channels` vem vazio: ainda não responde ninguém. Guarde o `id`. ```javascript const res = await fetch("https://api.zavu.dev/v2/agents", { method: "POST", headers: { Authorization: `Bearer ${process.env.ZAVUDEV_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "Assistente Loja Aurora", provider: "zavu", model: "openai/gpt-4o-mini", systemPrompt: SYSTEM_PROMPT, }), }); const { agent } = await res.json(); console.log(agent.id, agent.enabled); // "kh7...", false ``` O prompt de sistema é onde a maioria dos chatbots erra. "Responda só com a base de conhecimento" e "nunca invente prazo de entrega" são as duas linhas que impedem um bot de e-commerce de prometer o que o seu estoque não consegue cumprir. ## 3. Carregar as suas políticas numa base de conhecimento (v1) Uma base de conhecimento é um conjunto de documentos que o agente consulta antes de responder. Crie uma no agente e adicione um documento por assunto: ```bash curl -X POST https://api.zavu.dev/v1/agents/$AGENT_ID/knowledge-bases \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Políticas da loja", "description": "Frete, trocas, pagamentos e perguntas frequentes"}' ``` ```bash curl -X POST https://api.zavu.dev/v1/agents/$AGENT_ID/knowledge-bases/$KB_ID/documents \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Política de frete", "content": "# Frete\n\nPedidos pagos até as 14h (horário de Brasília) são despachados no mesmo dia útil.\nFrete padrão para todo o Brasil: 3 a 8 dias úteis, grátis em compras acima de R$ 199.\nFrete expresso para capitais do Sudeste: 1 a 2 dias úteis, R$ 29,90.\nPedidos pagos por boleto são despachados após a compensação." }' ``` Repita para trocas e devoluções, formas de pagamento (Pix, cartão, boleto, o que você aceita) e perguntas frequentes. Um documento por assunto é recuperado melhor do que um documento longo com tudo. Cada documento é processado depois de criado; o `isProcessed` vira `true` quando ele já está dividido e pode ser buscado. Se você vende na Nuvemshop ou na Shopify, esse texto você já tem: está nas páginas de política da sua loja. Cole como está e corrija o que estiver desatualizado. O agente vai repetir para os seus clientes exatamente o que estiver escrito. ## 4. Dar a ele uma tool `get_order_status` (v1) A base de conhecimento responde "quantos dias leva o frete". Ela não responde "cadê o pedido 1042". Para isso o agente chama uma tool: um endpoint HTTPS seu que a Zavu chama com os argumentos que o modelo preenche. ```bash curl -X POST https://api.zavu.dev/v1/agents/$AGENT_ID/tools \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "get_order_status", "description": "Consulta o status de um pedido. Use quando o cliente perguntar onde está o pedido ou quando chega. Precisa do número do pedido e do e-mail da compra.", "webhookUrl": "https://lojaaurora.com.br/zavu/tools/order-status", "parameters": { "type": "object", "properties": { "order_number": { "type": "string", "description": "Número do pedido, por exemplo 1042" }, "email": { "type": "string", "description": "E-mail usado na compra" } }, "required": ["order_number", "email"] } }' ``` O `201` traz `tool.webhookSecret`. **Ele só é devolvido na criação**, nunca numa leitura posterior. Guarde. Se perder, gere outro com `POST /v1/agents/{agentId}/tools/{toolId}/webhook/secret`. ### O que o seu endpoint recebe A Zavu envia um `POST` com este corpo JSON: ```json { "tool": "get_order_status", "arguments": { "order_number": "1042", "email": "camila@example.com" }, "context": { "conversationId": "js72...", "channel": "telegram", "contactPhone": "...", "messageId": "jd7..." }, "timestamp": 1760889600000 } ``` e estes headers: `X-Zavu-Tool` (o nome da tool), `X-Zavu-Timestamp`, e `X-Zavu-Signature`, o HMAC-SHA256 em hexadecimal do corpo bruto com o segredo da tool. Sem prefixo e sem o timestamp misturado. `contactPhone` é o identificador de onde o cliente escreveu: o número no WhatsApp, o chat id no Telegram. ### O endpoint ```javascript import express from "express"; import crypto from "node:crypto"; const app = express(); const SECRET = process.env.ZAVU_TOOL_SECRET; // Corpo bruto: a assinatura é sobre os bytes exatos que a Zavu enviou. app.post("/zavu/tools/order-status", express.raw({ type: "application/json" }), async (req, res) => { const expected = crypto.createHmac("sha256", SECRET).update(req.body).digest("hex"); const received = req.get("X-Zavu-Signature") ?? ""; const ok = received.length === expected.length && crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected)); if (!ok) return res.status(401).json({ error: "assinatura inválida" }); const { arguments: args } = JSON.parse(req.body.toString("utf8")); // A sua loja: a API da Nuvemshop, a da Shopify ou o seu próprio banco de dados. const order = await findOrder(args.order_number); // Não confirme um pedido para quem não consegue provar que ele é seu. if (!order || order.email.toLowerCase() !== String(args.email).toLowerCase()) { return res.json({ found: false }); } res.json({ found: true, status: order.status, // "pago" | "enviado" | "entregue" | ... carrier: order.carrier ?? null, // Correios, Jadlog, Loggi... trackingUrl: order.trackingUrl ?? null, estimatedDelivery: order.estimatedDelivery ?? null, }); }); app.listen(3000); ``` A mesma verificação em Python: ```python import hmac, hashlib def valid(raw_body: bytes, signature: str, secret: str) -> bool: expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature or "") ``` O que você devolve é o que o agente lê, então devolva dados, não texto pronto: um status, uma transportadora, um link de rastreio, uma data quando houver. Uma resposta que não é 2xx chega ao agente como chamada com falha e ele responde contornando o erro, então um `found: false` com `200` gera uma resposta melhor do que um `404`. Mantenha o endpoint rápido: o cliente está esperando a resposta enquanto ele roda. Pedir o e-mail é uma escolha sua, não uma exigência da Zavu. No Telegram você não tem um número para comparar com o pedido, e um número de pedido sozinho é fácil de adivinhar. Como o endpoint lida com dados pessoais do cliente, trate o que ele devolve com o cuidado que a LGPD já exige da sua loja: só o necessário para responder. ## 5. Conectar o agente e ligar (v2) ```bash curl -X POST https://api.zavu.dev/v2/agents/$AGENT_ID/channels \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{"address": "@loja_aurora_bot", "type": "telegram"}' ``` `address` e `type` são uma entrada de `GET /v2/channels`. Um endereço responde com um agente por vez: se outro agente já estiver nele, o `400` diz qual. Um endereço que o projeto não tem é `404 not_found`. O SMS de mão única é recusado com `409 channel_cannot_receive`, porque ninguém consegue responder a ele e o agente nunca responderia. Depois ative: ```bash curl -X PATCH https://api.zavu.dev/v2/agents/$AGENT_ID \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{"enabled": true}' ``` ## 6. Testar sem mandar mensagem para ninguém (v2) `POST /v2/agents/{agentId}/test` roda o prompt, o modelo e a base de conhecimento do agente contra uma mensagem e devolve a resposta em vez de enviá-la. Nenhuma mensagem sai e nenhuma execução é registrada. ```bash curl -X POST https://api.zavu.dev/v2/agents/$AGENT_ID/test \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "message": "o e-mail é camila@example.com", "history": [ { "role": "user", "content": "oi, cadê meu pedido 1042?" }, { "role": "assistant", "content": "Vou verificar. Qual e-mail você usou na compra?" } ] }' ``` A resposta: ```json { "success": true, "text": "...", "knowledgeChunksUsed": 0, "plannedToolCalls": [ { "name": "get_order_status", "arguments": "{\"order_number\":\"1042\",\"email\":\"camila@example.com\"}" } ], "executedToolCalls": [], "warnings": [ "The model was offered 1 tool (get_order_status) but none ran, since running them would reach your real handlers. ..." ], "inputTokens": 812, "outputTokens": 41, "latencyMs": 1430, "cost": 0.000146 } ``` Olhe três campos: - **`plannedToolCalls`**: a tool que o modelo escolheu e os argumentos que preencheu. Por padrão nada roda, então a resposta para nessa escolha. - **`knowledgeChunksUsed`**: pergunte "vocês despacham pedido pago no boleto na hora?" e deve vir acima de zero. Zero quer dizer que a resposta não veio dos seus documentos. - **`warnings`** (em inglês): o que um teste a seco não consegue provar. Um agente desativado, um agente sem canal conectado, tools oferecidas mas não executadas, fluxos que não foram avaliados, metadados de contato que não existem num teste. Para rodar o loop completo, o modelo chamando o seu endpoint real e respondendo com o resultado, adicione `"executeTools": true`. O seu endpoint é chamado de verdade, e `executedToolCalls` lista o que rodou com `ok` e o `error`, se houver. Use um pedido de teste. Um teste num agente `zavu` é cobrado como uma resposta real, pelo mesmo preço por token, e o `cost` da resposta diz quanto. Com saldo zerado ele é recusado com `402 insufficient_balance`; num agente com a sua própria key quem cobra é o seu provedor. Depois mande uma mensagem para o bot da sua própria conta do Telegram. Essa é a primeira conversa real. ## 7. Acompanhar as conversas e assumir No painel, cada chat que o agente atende aparece em **Conversas**, junto com as mensagens de todos os outros canais. Você pode abrir uma conversa e responder. Vale ser preciso sobre o que essa resposta faz. **Responder em Conversas não pausa o agente.** A próxima mensagem do cliente é respondida pelo agente de novo. O agente só fica quieto enquanto há uma transferência aberta, e uma transferência abre quando um fluxo chega a um passo `transfer`. Então dê ao cliente um jeito de pedir uma pessoa. Fluxos são v1: ```bash curl -X POST https://api.zavu.dev/v1/agents/$AGENT_ID/flows \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Falar com uma pessoa", "trigger": { "type": "keyword", "keywords": ["atendente", "humano", "falar com alguém"] }, "steps": [ { "id": "transferencia", "type": "transfer", "config": { "message": "Alguém da nossa equipe vai te responder por aqui em breve." } } ], "enabled": true, "priority": 10 }' ``` Um trigger `keyword` procura a palavra dentro da mensagem, sem diferenciar maiúsculas. Quando dispara, o cliente recebe a mensagem, a sessão fica `transferred` e o agente para de responder aquele contato. As próximas mensagens continuam chegando em Conversas. Assim que alguém da sua equipe responde, por Conversas ou pela API, a transferência termina e o agente retoma a conversa. Ninguém é avisado por você: não há fila nem atribuição. Se a sua equipe não acompanha Conversas, coloque um passo `tool` antes do `transfer` que avise o seu Slack ou o seu sistema de atendimento. Para a diferença entre isso e um bot de menu, leia [agente de IA vs chatbot](/pt/blog/ai-agent-vs-chatbot). ## O que pode dar errado | O que você vê | Por quê | O que fazer | |---|---|---| | `400 invalid_bot_token` | O Telegram recusou o token | Copie de novo no @BotFather | | `400` citando `name, provider, model, systemPrompt` | Faltam campos na criação | Envie os quatro | | `400` "already answered by the agent ..." | O endereço já tem outro agente | Desconecte lá ou use outro endereço | | `409 channel_cannot_receive` | Você conectou SMS de mão única | Use um canal em que o cliente consiga responder | | `402 insufficient_balance` no teste | Modelo da Zavu, saldo zerado | Adicione saldo ou use a sua própria key | | O agente responde mas inventa prazos | Ele não está chamando a tool | Confira `plannedToolCalls`; melhore a `description` da tool | | `knowledgeChunksUsed: 0` | Documentos não processados ou pouco relevantes | Confira `isProcessed`; divida documentos longos por assunto | Os erros da v2 são planos, `{code, message, details}`. A [referência de erros](https://docs.zavu.dev/api-v2/errors) lista todos. ## Indo para produção com o seu chatbot com IA para loja virtual - **Vá para o canal que os seus clientes usam.** Conecte WhatsApp ou Instagram em **Canais** e depois `POST /v2/agents/{agentId}/channels` com esse endereço. Mesmo agente, mesma base de conhecimento, mesma tool: o bot de teste no Telegram vira o chatbot de WhatsApp da sua loja sem reescrever nada. - **Custos do WhatsApp.** A Meta cobra as mensagens de serviço que passam das 1.000 gratuitas por número por mês, e deixa de entregá-las se a conta do WhatsApp Business não tiver forma de pagamento. [Veja como funciona](/pt/blog/whatsapp-service-messages-payment-method). - **Custo do agente.** Com `zavu`, cada resposta é cobrada do seu saldo por token. Você acompanha nas execuções e estatísticas do agente (v1: `GET /v1/agents/{agentId}/executions` e `/stats`, ou a página do agente no painel). - **Limites.** Os limites diários e mensais de envio dependem do seu plano e da sua verificação. A página de [limites de envio](https://docs.zavu.dev/concepts/sending-limits) tem os números. - **Mantenha as políticas em dia.** Se o prazo de troca mudar, atualize o documento (um `PATCH` no documento processa de novo). O bot repete o que a base de conhecimento diz, inclusive o que está desatualizado. Se você quer começar um chatbot de WhatsApp do zero, [como criar um chatbot de WhatsApp](/pt/blog/como-crear-chatbot-whatsapp) cobre esse caminho. Para ver onde isto se encaixa na nova API, leia [o anúncio da Zavu 2.0](/pt/blog/zavu-2-0) e a [visão geral da v2](https://docs.zavu.dev/api-v2/overview).