AI AgentsEcommerceTiendanubeWhatsAppTelegramTutorialAPI v2

Chatbot con IA para tienda online: responde con tus políticas y dice dónde está el pedido

Cómo crear un chatbot con IA para tienda online con la API de Zavu: responde con tus políticas de envío y devoluciones, consulta pedidos y pasa a una persona.

Redactado por: Zavu TeamRevisado por: Jennifer Villalobos19 de octubre de 202613 min de lectura
Ver como Markdown

TL;DR

  • Responde con tus políticas. El agente busca en una base de conocimiento con tus documentos de envíos, devoluciones y preguntas frecuentes antes de contestar.
  • El estado del pedido sale de tu tienda. Una tool get_order_status llama a tu endpoint HTTPS, que verifica la firma y devuelve el estado real.
  • Lo pruebas sin escribirle a clientes. POST /v2/agents/{agentId}/test devuelve la respuesta y la tool que eligió el modelo; con el proveedor zavu la prueba se cobra como una respuesta real.
  • Empiezas en Telegram y cambias de canal después. Telegram se conecta con una llamada a la API; WhatsApp e Instagram, desde Canales en el dashboard, con el mismo agente.
  • Responder desde la bandeja no pausa al agente. Solo lo pausa el paso transfer de un flujo, hasta que alguien de tu equipo responde.

Una tienda online recibe casi siempre las mismas cinco preguntas: dónde está mi pedido, cuánto cuesta el envío, puedo devolverlo, lo tienen en otra talla, cuánto demora en llegar. Un chatbot con IA para tienda online vale la pena cuando responde eso con tus políticas reales y tus pedidos reales, no con lo que el modelo se imagina.

Este tutorial lo arma sobre la API de Zavu, de punta a punta, con HTTP simple. Sirve igual si vendes en Tiendanube, Shopify o tu propio sitio. Al final tienes:

  • Un canal de chat conectado (Telegram para empezar, WhatsApp o Instagram cuando salgas a producción).
  • Un agente con IA que responde desde una base de conocimiento con tu política de envíos, de cambios y devoluciones, y tus preguntas frecuentes.
  • Una tool get_order_status: el agente llama a tu endpoint, tú verificas la firma y respondes con el estado del pedido desde tu tienda.
  • Una forma de probar todo sin escribirle a ningún cliente.
  • Una palabra clave que pasa la conversación a una persona, y el agente callado hasta que esa persona responde.

Si prefieres hacerlo con clics, el paso a paso del agente de soporte arma la versión de Telegram desde el dashboard, sin código. Este post es la versión por API, con tus pedidos dentro del loop.

Lo que necesitas

  • Una cuenta de Zavu y una API key. Todas las llamadas de abajo envían Authorization: Bearer $ZAVUDEV_API_KEY.
  • Un canal donde te escriben tus clientes. Cada uno cuesta distinto ponerlo en marcha:

- Telegram: un token de bot de @BotFather. Una llamada a la API, sin revisión, sin cuenta de Meta. La forma más rápida de tener algo real para probar. - WhatsApp: una cuenta de WhatsApp Business por el registro de Meta, conectada desde Canales en el dashboard. Es el canal con más fricción para conectar, y en México, Colombia, Chile o Argentina suele ser el que tus clientes realmente usan. - Instagram: también pasa por Meta, desde Canales en el dashboard.

  • Un endpoint HTTPS de tu lado que sepa buscar un pedido. Tiene que ser público: Zavu rechaza una tool cuya URL no es una dirección HTTPS pública.
  • Tus políticas en texto. Envíos, cambios y devoluciones, medios de pago, lo que respondes todas las semanas por DM.

Los SDKs (@zavudev/sdk, zavudev) llaman a la API v1. La API v2 se llama por HTTP, así que los ejemplos usan curl y fetch. Dos piezas de este armado todavía no tienen endpoint en v2, la base de conocimiento y las tools, y viven en v1 bajo /v1/agents/{agentId}/..., con la misma key y el mismo id de agente. La guía de migración lista lo que se queda en v1. Cada paso dice qué versión usa.

1. Conectar un canal (v2)

Parte con Telegram. Crea un bot con @BotFather, copia el token y conéctalo:

terminal
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..."}'

El 201 lista las entradas de la dirección que conectaste. La dirección de un bot de Telegram es @nombredelbot:

JSON
{ "items": [ { "address": "@tienda_lupita_bot", "type": "telegram", "active": true, "v1SenderId": "kd7..." } ] }

Si Telegram rechaza el token, no se crea nada y recibes 400 invalid_bot_token, con las palabras de Telegram en details.telegramSaid. Vuelve a copiar el token desde @BotFather.

Revisa active. Una conexión que en tu plan cuesta dinero nace apagada; la enciendes con POST /v2/channels/{address}/{type}/activate, y la respuesta dice cuánto cobró en chargedCents y monthlyCents. Detalle en Direcciones y canales.

WhatsApp e Instagram no se conectan con este endpoint. Se conectan desde Canales en el dashboard; una vez conectados aparecen en GET /v2/channels y el resto del tutorial funciona igual, con el número (por ejemplo +5215512345678) o el @usuario como dirección.

2. Crear el agente (v2)

terminal
curl -X POST https://api.zavu.dev/v2/agents \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Asistente Tienda Lupita", "provider": "zavu", "model": "openai/gpt-4o-mini", "systemPrompt": "Atiendes a clientes de Tienda Lupita, una tienda online de México. Responde solo con la base de conocimiento y la tool get_order_status. Si la respuesta no está ahí, di que no lo sabes y ofrece hablar con una persona. Para revisar un pedido, pide el número de pedido y el email de la compra. Nunca inventes una fecha de entrega. Respuestas cortas: esto es un chat. Tutea al cliente." }'

name, provider, model y systemPrompt son obligatorios, y v2 nombra todos los que faltan en un solo 400. provider es openai, anthropic, google, mistral o zavu.

zavu es el proveedor administrado: no necesitas API key propia y cada respuesta se cobra de tu saldo en Zavu por token. Con cualquier otro proveedor envías apiKey y los tokens se cobran en tu cuenta de ese proveedor. Con zavu, model se escribe como proveedor/modelo, por ejemplo openai/gpt-4o-mini; el selector de modelos del dashboard lista el catálogo vigente.

Dos cosas de la respuesta importan. El agente se crea desactivado, y su channels viene vacío: todavía no le responde a nadie. Guarda el 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: "Asistente Tienda Lupita", provider: "zavu", model: "openai/gpt-4o-mini", systemPrompt: SYSTEM_PROMPT, }), }); const { agent } = await res.json(); console.log(agent.id, agent.enabled); // "kh7...", false

El prompt de sistema es donde fallan la mayoría de los chatbots. "Responde solo con la base de conocimiento" y "nunca inventes una fecha de entrega" son las dos líneas que evitan que un bot de ecommerce prometa lo que tu bodega no puede cumplir.

3. Cargar tus políticas en una base de conocimiento (v1)

Una base de conocimiento es un conjunto de documentos que el agente busca antes de responder. Créala sobre el agente y agrega un documento por tema:

terminal
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 de la tienda", "description": "Envíos, cambios, pagos y preguntas frecuentes"}'
terminal
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 envíos", "content": "# Envíos\n\nLos pedidos pagados antes de las 14:00 (hora CDMX) salen el mismo día hábil.\nEnvío estándar a todo México: 3 a 6 días hábiles, gratis en compras desde $999 MXN.\nEnvío express a CDMX, Guadalajara y Monterrey: 1 a 2 días hábiles, $149 MXN.\nNo enviamos a apartados postales." }'

Repite para cambios y devoluciones, medios de pago (tarjeta, OXXO, transferencia, lo que uses) y preguntas frecuentes. Un documento por tema se recupera mejor que un documento largo con todo. Cada documento se procesa después de crearse; su isProcessed pasa a true cuando ya está dividido y se puede buscar.

Si vendes en Tiendanube o Shopify, este texto ya lo tienes: está en las páginas de políticas de tu tienda. Pégalo tal cual y corrige lo que esté viejo. El agente se lo va a repetir a tus clientes tal como está escrito.

4. Darle una tool get_order_status (v1)

La base de conocimiento responde "cuánto demora el envío". No puede responder "dónde está el pedido 1042". Para eso el agente llama a una tool: un endpoint HTTPS tuyo al que Zavu llama con argumentos que completa el modelo.

terminal
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 el estado de un pedido. Úsala cuando el cliente pregunte dónde está su pedido o cuándo llega. Necesita el número de pedido y el email de la compra.", "webhookUrl": "https://tiendalupita.mx/zavu/tools/order-status", "parameters": { "type": "object", "properties": { "order_number": { "type": "string", "description": "Número de pedido, por ejemplo 1042" }, "email": { "type": "string", "description": "Email usado en la compra" } }, "required": ["order_number", "email"] } }'

El 201 trae tool.webhookSecret. Solo se devuelve al crear la tool, nunca en una lectura posterior. Guárdalo. Si lo pierdes, rótalo con POST /v1/agents/{agentId}/tools/{toolId}/webhook/secret.

Lo que recibe tu endpoint

Zavu envía un POST con este cuerpo JSON:

JSON
{ "tool": "get_order_status", "arguments": { "order_number": "1042", "email": "mariana@example.com" }, "context": { "conversationId": "js72...", "channel": "telegram", "contactPhone": "...", "messageId": "jd7..." }, "timestamp": 1760889600000 }

y estos headers: X-Zavu-Tool (el nombre de la tool), X-Zavu-Timestamp, y X-Zavu-Signature, el HMAC-SHA256 en hexadecimal del cuerpo crudo con el secreto de la tool. Sin prefijo y sin el timestamp mezclado. contactPhone es el identificador desde el que escribió el cliente: su número en WhatsApp, el chat id en Telegram.

El endpoint

JavaScript
import express from "express"; import crypto from "node:crypto"; const app = express(); const SECRET = process.env.ZAVU_TOOL_SECRET; // Cuerpo crudo: la firma es sobre los bytes exactos que envió Zavu. 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: "firma inválida" }); const { arguments: args } = JSON.parse(req.body.toString("utf8")); // Tu tienda: la API de Tiendanube, la de Shopify o tu propia base de datos. const order = await findOrder(args.order_number); // No confirmes un pedido a quien no puede demostrar que es suyo. if (!order || order.email.toLowerCase() !== String(args.email).toLowerCase()) { return res.json({ found: false }); } res.json({ found: true, status: order.status, // "pagado" | "enviado" | "entregado" | ... carrier: order.carrier ?? null, // Estafeta, DHL, Servientrega, Andreani... trackingUrl: order.trackingUrl ?? null, estimatedDelivery: order.estimatedDelivery ?? null, }); }); app.listen(3000);

La misma verificación en 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 "")

Lo que devuelves es lo que lee el agente, así que devuelve datos, no prosa: un estado, una paquetería, un link de seguimiento, una fecha cuando la tengas. Una respuesta que no es 2xx le llega al agente como una llamada fallida y responde esquivando el error, así que un found: false con 200 da una mejor respuesta que un 404. Mantén el endpoint rápido: el cliente está esperando la respuesta mientras corre.

Pedir el email es una decisión tuya, no un requisito de Zavu. En Telegram no tienes un número para comparar con el pedido, y un número de pedido solo es fácil de adivinar.

5. Conectar el agente y encenderlo (v2)

terminal
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": "@tienda_lupita_bot", "type": "telegram"}'

address y type son una entrada de GET /v2/channels. Una dirección responde con un agente a la vez: si otro agente ya la tiene, el 400 dice cuál. Una dirección que el proyecto no tiene es 404 not_found. El SMS de una vía se rechaza con 409 channel_cannot_receive, porque nadie puede responderle y el agente nunca contestaría.

Después lo activas:

terminal
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. Probarlo sin escribirle a nadie (v2)

POST /v2/agents/{agentId}/test corre el prompt, el modelo y la base de conocimiento del agente contra un mensaje y te devuelve la respuesta en vez de enviarla. No sale ningún mensaje y no se registra ninguna ejecución.

terminal
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": "el email es mariana@example.com", "history": [ { "role": "user", "content": "hola, dónde está mi pedido 1042?" }, { "role": "assistant", "content": "Lo reviso. ¿Con qué email hiciste la compra?" } ] }'

La respuesta:

JSON
{ "success": true, "text": "...", "knowledgeChunksUsed": 0, "plannedToolCalls": [ { "name": "get_order_status", "arguments": "{\"order_number\":\"1042\",\"email\":\"mariana@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 }

Mira tres campos:

  • plannedToolCalls: la tool que eligió el modelo y los argumentos que completó. Por defecto no corre nada, así que la respuesta se detiene en esa elección.
  • knowledgeChunksUsed: pregunta "¿envían a apartados postales?" y debería ser mayor que cero. Cero significa que la respuesta no salió de tus documentos.
  • warnings (en inglés): lo que una prueba en seco no puede demostrar. Un agente desactivado, un agente sin canal conectado, tools ofrecidas pero no ejecutadas, flujos que no se evaluaron, metadatos de contacto que en una prueba no existen.

Para correr el loop completo, el modelo llamando a tu endpoint real y respondiendo con el resultado, agrega "executeTools": true. Tu endpoint se llama de verdad, y executedToolCalls lista lo que corrió con ok y el error si hubo. Usa un pedido de prueba.

Una prueba en un agente zavu se cobra igual que una respuesta real, al mismo precio por token, y el cost de la respuesta dice cuánto. Con el saldo en cero se rechaza con 402 insufficient_balance; en un agente con tu propia key la paga tu proveedor.

Después escríbele al bot desde tu propia cuenta de Telegram. Esa es la primera conversación real.

7. Ver las conversaciones y tomar el control

En el dashboard, cada chat que atiende el agente aparece en Conversaciones, junto a los mensajes de todos los demás canales. Puedes abrir un hilo y responder tú.

Conviene ser preciso con lo que hace esa respuesta. Responder desde Conversaciones no pausa al agente. El siguiente mensaje del cliente lo vuelve a contestar el agente. El agente solo se queda callado mientras hay un traspaso abierto, y un traspaso se abre cuando un flujo llega a un paso transfer.

Así que dale al cliente una forma de pedir una persona. Los flujos son v1:

terminal
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": "Hablar con una persona", "trigger": { "type": "keyword", "keywords": ["asesor", "humano", "hablar con alguien"] }, "steps": [ { "id": "traspaso", "type": "transfer", "config": { "message": "Alguien de nuestro equipo te responde por aquí en breve." } } ], "enabled": true, "priority": 10 }'

Un trigger keyword busca la palabra dentro del mensaje, sin distinguir mayúsculas. Cuando se dispara, el cliente recibe el mensaje, la sesión queda transferred y el agente deja de responderle a ese contacto. Sus siguientes mensajes siguen llegando a Conversaciones. En cuanto alguien de tu equipo responde, desde Conversaciones o desde la API, el traspaso termina y el agente retoma el hilo.

Nadie recibe un aviso por ti: no hay cola ni asignación. Si tu equipo no mira Conversaciones, pon un paso tool antes del transfer que avise a tu Slack o a tu sistema de soporte. Para la diferencia entre esto y un bot de menús, lee agente de IA vs chatbot.

Qué puede salir mal

Lo que vesPor quéQué hacer
400 invalid_bot_tokenTelegram rechazó el tokenCópialo de nuevo desde @BotFather
400 nombrando name, provider, model, systemPromptFaltan campos al crearEnvía los cuatro
400 "already answered by the agent ..."La dirección ya tiene otro agenteDesconéctalo allá o usa otra dirección
409 channel_cannot_receiveConectaste SMS de una víaUsa un canal donde el cliente pueda responder
402 insufficient_balance al probarModelo de Zavu, saldo en ceroCarga saldo o usa tu propia key
El agente responde pero inventa fechasNo está llamando a la toolRevisa plannedToolCalls; afina la description de la tool
knowledgeChunksUsed: 0Documentos sin procesar o poco relevantesRevisa isProcessed; divide documentos largos por tema

Los errores de v2 son planos, {code, message, details}. La referencia de errores los lista.

Salir a producción: tu chatbot con IA para tienda online en WhatsApp

  • Muévete al canal que usan tus clientes. Conecta WhatsApp o Instagram desde Canales y luego POST /v2/agents/{agentId}/channels con esa dirección. Mismo agente, misma base de conocimiento, misma tool: así el bot de prueba en Telegram pasa a ser tu chatbot para WhatsApp para ecommerce sin reescribir nada.
  • Costos de WhatsApp. Meta cobra los mensajes de servicio que pasan de los 1,000 gratis por número al mes, y deja de entregarlos si la cuenta de WhatsApp Business no tiene medio de pago. Aquí está cómo funciona.
  • Costo del agente. Con zavu, cada respuesta se cobra de tu saldo por token. Lo ves en las ejecuciones y estadísticas del agente (v1: GET /v1/agents/{agentId}/executions y /stats, o la página del agente en el dashboard).
  • Límites. Los límites diarios y mensuales de envío dependen de tu plan y tu verificación. La página de límites de envío tiene los números.
  • Mantén las políticas al día. Si cambia tu plazo de devolución, actualiza el documento (un PATCH sobre el documento lo vuelve a procesar). El bot repite lo que dice la base de conocimiento, incluido lo que está desactualizado.

Si buscas el enfoque de chatbot para WhatsApp desde cero, cómo crear un chatbot de WhatsApp lo cubre. Para ver dónde encaja esto en la nueva API, lee el anuncio de Zavu 2.0 y el resumen de v2.

Preguntas frecuentes

¿Un chatbot con IA para tienda online puede decir dónde está un pedido?
Sí, si le das una tool que lea tus pedidos. En Zavu creas una tool get_order_status con una URL de webhook; el agente llama a tu endpoint con el número de pedido, tú verificas el header X-Zavu-Signature y devuelves el estado desde Tiendanube, Shopify o tu base de datos. El modelo nunca adivina el estado.
¿Necesito una API key de OpenAI para armar el chatbot?
No. Con el proveedor zavu el agente usa un modelo administrado y cada respuesta se cobra de tu saldo en Zavu por token. Si prefieres tu propia cuenta, usa openai, anthropic, google o mistral como provider y envía apiKey; en ese caso los tokens los cobra ese proveedor y no Zavu.
¿Si respondo desde Conversaciones el agente deja de contestar?
No. Que una persona responda desde Conversaciones no pausa al agente: el siguiente mensaje del cliente lo vuelve a contestar el agente. El agente solo se queda callado después de que un flujo llega a un paso transfer, y retoma el hilo apenas alguien de tu equipo responde.
¿Cómo pruebo el chatbot sin escribirle a clientes reales?
Llama a POST /v2/agents/{agentId}/test con un mensaje y, si quieres, un historial. Corre el prompt, el modelo y la base de conocimiento y devuelve la respuesta, la tool elegida y advertencias, sin enviar nada. Las tools solo se ejecutan con executeTools en true. Con el proveedor zavu la prueba se cobra como una respuesta real.
¿Puedo usar el mismo chatbot en WhatsApp y en Telegram?
Sí. Un agente responde en cada dirección que conectas con POST /v2/agents/{agentId}/channels. Telegram se conecta con un token de bot por la API; WhatsApp e Instagram se conectan por Meta desde Canales en el dashboard. La base de conocimiento y las tools no cambian, así que el bot probado en Telegram pasa a WhatsApp igual.
¿La base de conocimiento y las tools son parte de la API v2 de Zavu?
Todavía no. Los agentes, los canales y las pruebas están en v2, pero la base de conocimiento, las tools y los flujos siguen en v1 bajo /v1/agents/{agentId}/. Las dos versiones usan la misma API key y comparten los datos, así que un agente creado en v2 se administra en v1 con el mismo id.

Necesitas ayuda? Contáctanos o únete a nuestra comunidad en Discord para soporte.

Get started

Listo para empezar?

Comienza a construir gratis, o agenda una llamada para discutir tu caso de uso específico.

Chatbot con IA para tienda online | Zavu Blog