Saltar al contenido principal
Deja que Sentra escriba tu código de integración por ti.
Usa nuestro asistente AI en VS Code, Cursor o Windsurf para generar código SDK/API, código de integración de LLM Blueprint, webhooks y más, solo describiendo lo que deseas.
Prueba Sentra: Integración Potenciada por AI →
En este tutorial, construirás una aplicación de chat AI con facturación automática basada en el uso. Crearemos todo desde cero: el medidor de facturación, la configuración del producto y el código de la aplicación que impulsa las conversaciones y rastrea el uso de tokens en tiempo real.
Este tutorial proporciona una aplicación completamente funcional con backend y frontend. La aplicación de chat utiliza Google Gemini AI y rastrea automáticamente el uso de tokens sin necesidad de conteo manual.
Al final de este tutorial, tendrás una aplicación de chat funcional que:
  • Impulsa conversaciones AI usando Google Gemini (AI SDK)
  • Rastreará automáticamente el uso de tokens (sin código manual)
  • Cobrará a los clientes según el consumo real de tokens
  • Incluye una hermosa interfaz de chat
Demostración de Chat AI

Lo que estamos construyendo

Comencemos por entender nuestro servicio de chat AI:
  • Servicio: Chat potenciado por AI usando Google Gemini (AI SDK)
  • Modelo de Precios: Pago por token ($0.01 por 1,000 tokens)
  • Nivel Gratuito: 10,000 tokens gratuitos por cliente por mes
  • Características: Historial de conversaciones, seguimiento automático de tokens
Antes de comenzar, asegúrate de tener:

Paso 1: Crea tu Medidor de Uso

Comenzaremos creando un medidor en tu panel de Dodo Payments que rastreará el uso de tokens AI.
Lo que estamos construyendo: Un medidor llamado “Medidor de Uso de Tokens AI” que suma todos los tokens consumidos en conversaciones de chat.
1

Abre la sección de Medidores

  1. Inicia sesión en tu panel de Dodo Payments
  2. Haz clic en Productos en la barra lateral izquierda
  3. Haz clic en Medidores
  4. Haz clic en el botón Crear Medidor
Crear Medidor
Deberías ver un formulario donde configuraremos nuestro seguimiento de tokens.
2

Completa la información básica del medidor

Ahora ingresaremos los detalles específicos para nuestro servicio de chat AI:Nombre del MedidorAI Token Usage MeterDescripciónTracks token consumption from AI chat conversations using AI SDKNombre del Eventoai_chat_usage
El nombre del evento ai_chat_usage debe coincidir exactamente con lo que enviaremos desde nuestro código de aplicación más tarde. ¡Los nombres de los eventos son sensibles a mayúsculas y minúsculas!
3

Configura cómo contamos los tokens

Configura la agregación (cómo el medidor cuenta nuestros eventos):Tipo de Agregación: Selecciona Suma del menú desplegableAgregarse Sobre: Tipo → totalTokensUnidad de Medida: Tipo → tokens
Estamos usando “Suma” porque queremos sumar todos los tokens consumidos a través de múltiples mensajes de chat. El SDK envía automáticamente totalTokens en cada evento.
4

Crea tu medidor

  1. Verifica que todas tus configuraciones coincidan con los valores anteriores
  2. Haz clic en Crear Medidor
Configuración del Medidor
¡Medidor creado! Tu “Medidor de Uso de Tokens AI” ahora está listo para comenzar a contar tokens. A continuación, lo conectaremos a un producto de facturación.

Paso 2: Obtén tus Claves API

Antes de construir la aplicación, recojamos las claves API que necesitaremos.
1

Obtén la Clave API de Dodo Payments

  1. En tu panel de Dodo Payments, ve a DesarrolladoresClaves API
  2. Haz clic en Crear Clave API
  3. Copia la clave API - se verá como test_abc123...
Guarda esta clave API - la agregaremos a nuestro .env archivo más tarde.
2

Obtén la Clave API de Google AI

  1. Visita aistudio.google.com
  2. Haz clic en Obtener Clave API
  3. Crea una nueva clave API o usa una existente
  4. Copia la clave
Mantén esta clave a salvo - también la agregaremos a nuestro .env archivo.

Paso 3: Crea tu Producto de Facturación

Ahora necesitamos crear un producto que defina nuestro precio ($0.01 por 1,000 tokens con 10,000 tokens gratuitos). Esto conecta nuestro medidor a la facturación real.
Lo que estamos construyendo: Un producto llamado “Servicio de Chat AI” que cobra según el consumo de tokens con un generoso nivel gratuito.
1

Navega a Productos

  1. En tu panel de Dodo Payments, haz clic en Productos en la barra lateral izquierda
  2. Haz clic en Crear Producto
  3. Selecciona Basado en Uso como el tipo de producto
Esto le dice a Dodo Payments que la facturación se basará en el uso del medidor, no en una suscripción fija.
2

Ingresa los detalles del producto

Completa los detalles requeridos:Nombre del Producto: → AI Chat ServiceDescripción: → AI-powered chat service with automatic token-based billingImagen del Producto: Sube una imagen relevante
Estas aparecerán en las facturas de los clientes, así que hazlas claras y profesionales.
3

Conecta tu medidor

Antes de conectar tu medidor, asegúrate de haber seleccionado Facturación Basada en Uso como el tipo de precio para tu producto.Además, establece el Precio Fijo en 0 para asegurarte de que los clientes solo sean cobrados según su uso, sin tarifa base.Ahora, vincula el medidor que acabas de crear:
  1. Desplázate hacia abajo a la sección Medidor Asociado
  2. Haz clic en Agregar Medidores
  3. Desde el menú desplegable, selecciona “Medidor de Uso de Tokens AI” (el que creaste anteriormente)
  4. Confirma que aparece en la configuración de tu producto
Tu medidor ahora está conectado exitosamente a este producto.
4

Establece tu precio

Aquí es donde definimos nuestro modelo de negocio:Precio Por Unidad: Ingresa → 0.00001 (esto es 0.01por1,000tokenso0.01 por 1,000 tokens o 0.00001 por token)Umbral Gratuito: Ingresa → 10000 (los clientes obtienen 10,000 tokens gratuitos por mes)
Precios del Producto
Cómo funciona la facturación: Si un cliente usa 25,000 tokens en un mes, se le cobrará por 15,000 tokens (25,000 - 10,000 gratuitos) = 15,000 × 0.00001=0.00001 = 0.15
5

Guarda tu producto

  1. Revisa todas tus configuraciones:
    • Nombre: Servicio de Chat AI
    • Medidor: Medidor de Uso de Tokens AI
    • Precio: $0.01 por 1,000 tokens
    • Nivel gratuito: 10,000 tokens
  2. Haz clic en Guardar Cambios
¡Producto creado! Tu facturación ahora está configurada. Los clientes serán cobrados automáticamente según su uso de tokens.

Paso 4: Realiza una Compra de Prueba

Antes de comenzar a construir la aplicación, creemos un cliente de prueba realizando una compra.
1

Obtén tu enlace de pago

  1. En tu panel de Dodo Payments, ve a Productos
  2. Encuentra tu producto “Servicio de Chat AI”
  3. Haz clic en el botón Compartir junto a tu producto
  4. Copia el enlace de pago que aparece
2

Completa una compra de prueba

  1. Abre el enlace de pago en una nueva pestaña del navegador
  2. Ingresa los detalles de pago de prueba y completa la compra
Después de un pago exitoso, tendrás un ID de cliente que usaremos en nuestro código de aplicación.
3

Encuentra tu ID de cliente

  1. Regresa a tu panel de Dodo Payments
  2. Navega a Ventas -> Clientes en la barra lateral izquierda
  3. Encuentra el cliente que acabas de crear (con el correo electrónico de prueba)
  4. Copia el ID de cliente - se verá como cus_123
Guarda este ID de cliente - lo usaremos al probar nuestra aplicación de chat.

Paso 5: Construye la Aplicación de Chat

Ahora tenemos nuestra configuración de facturación completa y un cliente de prueba creado. Vamos a construir la aplicación de chat AI con seguimiento automático de tokens.
1

Configura tu proyecto

Crea un nuevo directorio e inicializa el proyecto:
mkdir ai-chat-app
cd ai-chat-app
npm init -y
2

Instala dependencias

Instala los paquetes que necesitamos:
npm install express ai @ai-sdk/google @dodopayments/ingestion-blueprints dotenv
npm install --save-dev typescript @types/express @types/node tsx
3

Configura TypeScript

Crea tsconfig.json:
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}
Actualiza package.json para agregar el tipo de módulo y scripts:
package.json
{
  "type": "module",
  "scripts": {
    "dev": "tsx src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}
4

Crea la estructura del proyecto

Crea las carpetas y archivos:
mkdir src public
5

Configura las variables de entorno

Crea un archivo .env en la raíz de tu proyecto:
.env
DODO_PAYMENTS_API_KEY=your_dodo_api_key_here
DODO_ENVIRONMENT=test_mode
GOOGLE_GENERATIVE_AI_API_KEY=your_google_api_key_here
PORT=3000
Reemplaza los valores de marcador de posición con tus claves API reales del Paso 2.
6

Crea el servidor backend

Crea src/server.ts y copia este código completo del servidor:
Aquí está el servidor de chat AI completo con facturación integrada:
import express, { Request, Response } from 'express';
import { generateText } from 'ai';
import { google } from '@ai-sdk/google';
import { createLLMTracker } from '@dodopayments/ingestion-blueprints';
import 'dotenv/config';

const app = express();
app.use(express.json());
app.use(express.static('public'));

// Replace with your test customer ID
const CUSTOMER_ID = 'cus_123';

// Create tracker once with your meter event name
const llmTracker = createLLMTracker({
  apiKey: process.env.DODO_PAYMENTS_API_KEY!,
  environment: process.env.DODO_ENVIRONMENT as 'test_mode' | 'live_mode',
  eventName: 'ai_chat_usage', // Must match your meter configuration
});

// Chat endpoint with conversation support
app.post('/chat', async (req: Request, res: Response) => {
  try {
    const { messages } = req.body;

    if (!messages || !Array.isArray(messages)) {
      return res.status(400).json({ 
        error: 'Missing required field: messages (array)' 
      });
    }

    // Wrap AI SDK with automatic token tracking
    const trackedClient = llmTracker.wrap({
      client: { generateText },
      customerId: CUSTOMER_ID
    });

    // Generate AI response - tokens are automatically tracked!
    const response = await trackedClient.generateText({
      model: google('gemini-2.5-flash'),
      messages: messages
    });

    res.json({
      message: response.text,
      usage: {
        totalTokens: response.usage.totalTokens
      }
    });

  } catch (error: any) {
    console.error('Chat error:', error);
    res.status(500).json({ 
      error: 'Failed to process chat',
      details: error.message 
    });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`🚀 Server running at http://localhost:${PORT}`);
  console.log(`📊 Tracking event: ai_chat_usage`);
  console.log(`👤 Customer ID: ${CUSTOMER_ID}`);
  console.log(`🔧 Environment: ${process.env.DODO_ENVIRONMENT}`);
});

Paso 6: Agrega la Interfaz de Chat

Ahora agreguemos una hermosa interfaz de chat con todo el historial de conversaciones. Crea public/index.html:
public/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>AI Chat with Usage Billing</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
          Roboto, sans-serif;
        background: #0f0f1e;
        background-image: radial-gradient(
            at 0% 0%,
            rgba(102, 126, 234, 0.15) 0px,
            transparent 50%
          ),
          radial-gradient(
            at 100% 100%,
            rgba(118, 75, 162, 0.15) 0px,
            transparent 50%
          ),
          radial-gradient(
            at 50% 50%,
            rgba(102, 126, 234, 0.05) 0px,
            transparent 50%
          );
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        padding: 0;
        position: relative;
        overflow: hidden;
        margin: 0;
      }

      .chat-container {
        background: rgba(22, 22, 35, 0.95);
        border: 1px solid rgba(102, 126, 234, 0.2);
        border-radius: 0;
        box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
        width: 100%;
        max-width: 100%;
        height: 100vh;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        position: relative;
        z-index: 1;
      }

      .chat-header {
        background: linear-gradient(
          135deg,
          rgba(102, 126, 234, 0.15) 0%,
          rgba(118, 75, 162, 0.15) 100%
        );
        border-bottom: 1px solid rgba(102, 126, 234, 0.2);
        color: white;
        padding: 24px 28px;
        position: relative;
        overflow: hidden;
      }

      .chat-header h1 {
        font-size: 26px;
        margin-bottom: 6px;
        font-weight: 700;
        letter-spacing: -0.5px;
        color: #fff;
      }

      .chat-header p {
        font-size: 13px;
        opacity: 0.6;
        font-weight: 500;
        letter-spacing: 0.3px;
      }

      .chat-messages {
        flex: 1;
        overflow-y: auto;
        padding: 32px 10%;
        background: transparent;
        will-change: scroll-position;
        scroll-behavior: smooth;
      }

      .chat-messages::-webkit-scrollbar {
        width: 6px;
      }

      .chat-messages::-webkit-scrollbar-track {
        background: rgba(255, 255, 255, 0.05);
      }

      .chat-messages::-webkit-scrollbar-thumb {
        background: rgba(102, 126, 234, 0.3);
        border-radius: 3px;
      }

      .chat-messages::-webkit-scrollbar-thumb:hover {
        background: rgba(102, 126, 234, 0.5);
      }

      .message {
        margin-bottom: 20px;
        display: flex;
        gap: 12px;
        animation: slideIn 0.2s ease-out;
      }

      @keyframes slideIn {
        from {
          opacity: 0;
          transform: translateY(10px);
        }

        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .message.user {
        flex-direction: row-reverse;
      }

      .message-avatar {
        width: 40px;
        height: 40px;
        border-radius: 12px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 20px;
        flex-shrink: 0;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
      }

      .message.user .message-avatar {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      }

      .message.assistant .message-avatar {
        background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
      }

      .message-content {
        max-width: 65%;
      }

      .message-bubble {
        padding: 14px 18px;
        border-radius: 18px;
        line-height: 1.6;
        word-wrap: break-word;
        font-size: 15px;
        position: relative;
      }

      .message.user .message-bubble {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border-bottom-right-radius: 6px;
        box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
      }

      .message.assistant .message-bubble {
        background: rgba(255, 255, 255, 0.05);
        color: rgba(255, 255, 255, 0.95);
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-bottom-left-radius: 6px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
      }

      .message-meta {
        display: flex;
        gap: 10px;
        margin-top: 8px;
        font-size: 11px;
        color: rgba(255, 255, 255, 0.4);
        font-weight: 500;
      }

      .message.user .message-meta {
        justify-content: flex-end;
      }

      .token-badge {
        background: rgba(102, 126, 234, 0.2);
        color: #a8b9ff;
        padding: 4px 10px;
        border-radius: 12px;
        font-weight: 600;
        border: 1px solid rgba(102, 126, 234, 0.3);
      }

      .chat-input-area {
        padding: 24px 10% 32px;
        background: rgba(22, 22, 35, 0.95);
        border-top: 1px solid rgba(102, 126, 234, 0.2);
      }

      .input-wrapper {
        display: flex;
        gap: 12px;
        align-items: flex-end;
      }

      #messageInput {
        flex: 1;
        background: rgba(255, 255, 255, 0.05);
        border: 2px solid rgba(102, 126, 234, 0.2);
        border-radius: 16px;
        padding: 14px 20px;
        font-size: 15px;
        font-family: inherit;
        resize: none;
        max-height: 120px;
        transition: border-color 0.2s ease, background 0.2s ease;
        color: white;
        will-change: border-color;
        overflow: hidden;
        scrollbar-width: none;
        /* Firefox */
      }

      #messageInput::-webkit-scrollbar {
        display: none;
      }

      #messageInput::placeholder {
        color: rgba(255, 255, 255, 0.3);
      }

      #messageInput:focus {
        outline: none;
        border-color: #667eea;
        background: rgba(255, 255, 255, 0.08);
      }

      #sendBtn {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border: none;
        width: 52px;
        height: 52px;
        border-radius: 16px;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 22px;
        transition: transform 0.1s ease, box-shadow 0.1s ease;
        flex-shrink: 0;
        box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
        position: relative;
      }

      #sendBtn:hover:not(:disabled) {
        transform: translateY(-1px);
        box-shadow: 0 4px 12px rgba(102, 126, 234, 0.5);
      }

      #sendBtn:active:not(:disabled) {
        transform: translateY(0);
      }

      #sendBtn:disabled {
        opacity: 0.4;
        cursor: not-allowed;
        box-shadow: none;
      }

      .typing-indicator {
        display: none;
        padding: 14px 18px;
        background: rgba(255, 255, 255, 0.05);
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: 18px;
        border-bottom-left-radius: 6px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
        width: fit-content;
      }

      .typing-indicator.show {
        display: block;
      }

      .typing-dots {
        display: flex;
        gap: 6px;
      }

      .typing-dots span {
        width: 10px;
        height: 10px;
        border-radius: 50%;
        background: #667eea;
        animation: typing 1.4s infinite ease-in-out;
        will-change: transform, opacity;
      }

      .typing-dots span:nth-child(2) {
        animation-delay: 0.2s;
      }

      .typing-dots span:nth-child(3) {
        animation-delay: 0.4s;
      }

      @keyframes typing {
        0%,
        60%,
        100% {
          transform: translateY(0) scale(1);
          opacity: 0.6;
        }

        30% {
          transform: translateY(-12px) scale(1.1);
          opacity: 1;
        }
      }

      .error-message {
        background: rgba(239, 68, 68, 0.15);
        color: #fca5a5;
        padding: 14px 18px;
        border-radius: 12px;
        margin-bottom: 12px;
        display: none;
        border: 1px solid rgba(239, 68, 68, 0.3);
        font-size: 14px;
        font-weight: 500;
      }

      .error-message.show {
        display: block;
        animation: slideIn 0.3s ease;
      }

      .empty-state {
        text-align: center;
        padding: 80px 20px;
        color: rgba(255, 255, 255, 0.5);
      }

      .empty-state-icon {
        font-size: 72px;
        margin-bottom: 20px;
        animation: float 3s ease-in-out infinite;
      }

      @keyframes float {
        0%,
        100% {
          transform: translateY(0px);
        }

        50% {
          transform: translateY(-10px);
        }
      }

      .empty-state h2 {
        font-size: 24px;
        margin-bottom: 10px;
        color: rgba(255, 255, 255, 0.9);
        font-weight: 700;
        letter-spacing: -0.5px;
      }

      .empty-state p {
        font-size: 15px;
        color: rgba(255, 255, 255, 0.4);
        font-weight: 500;
      }
    </style>
  </head>

  <body>
    <div class="chat-container">
      <div class="chat-header">
        <h1>🤖 AI Chat Assistant</h1>
        <p>Powered by AI-SDK & Dodo Payments</p>
      </div>

      <div class="chat-messages" id="chatMessages">
        <div class="empty-state" id="emptyState">
          <div class="empty-state-icon">💬</div>
          <h2>Start a Conversation</h2>
          <p>Ask me anything! Your token usage is automatically tracked.</p>
        </div>
      </div>

      <div class="chat-input-area">
        <div class="error-message" id="errorMessage"></div>
        <div class="input-wrapper">
          <textarea
            id="messageInput"
            placeholder="Type your message here..."
            rows="1"
          ></textarea>
          <button id="sendBtn" onclick="sendMessage()"></button>
        </div>
      </div>
    </div>

    <script>
      let conversationHistory = [];

      const messageInput = document.getElementById("messageInput");
      let resizeTimeout;
      messageInput.addEventListener("input", function () {
        clearTimeout(resizeTimeout);
        resizeTimeout = setTimeout(() => {
          this.style.height = "auto";
          this.style.height = Math.min(this.scrollHeight, 120) + "px";
        }, 10);
      });

      // Send message on Enter (Shift+Enter for new line)
      messageInput.addEventListener("keydown", function (e) {
        if (e.key === "Enter" && !e.shiftKey) {
          e.preventDefault();
          sendMessage();
        }
      });

      async function sendMessage() {
        const input = document.getElementById("messageInput");
        const message = input.value.trim();

        if (!message) return;

        // Hide empty state
        document.getElementById("emptyState").style.display = "none";

        // Hide error
        document.getElementById("errorMessage").classList.remove("show");

        // Add user message to UI
        addMessage("user", message);

        // Add to conversation history
        conversationHistory.push({
          role: "user",
          content: message,
        });

        // Clear input
        input.value = "";
        input.style.height = "auto";

        // Show typing indicator
        showTypingIndicator();

        // Disable send button
        const sendBtn = document.getElementById("sendBtn");
        sendBtn.disabled = true;

        try {
          const response = await fetch("/chat", {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify({
              messages: conversationHistory,
            }),
          });

          const data = await response.json();

          if (!response.ok) {
            throw new Error(data.error || "Failed to get response");
          }

          // Hide typing indicator
          hideTypingIndicator();

          // Add assistant response to UI
          addMessage("assistant", data.message, data.usage);

          // Add to conversation history
          conversationHistory.push({
            role: "assistant",
            content: data.message,
          });
        } catch (error) {
          hideTypingIndicator();
          showError(error.message);
          // Remove the last user message from history since it failed
          conversationHistory.pop();
        } finally {
          sendBtn.disabled = false;
        }
      }

      function addMessage(role, content, usage = null) {
        const messagesDiv = document.getElementById("chatMessages");

        const messageDiv = document.createElement("div");
        messageDiv.className = `message ${role}`;

        const avatar = role === "user" ? "👤" : "🤖";

        let metaHTML = "";
        if (usage) {
          metaHTML = `
                    <div class="message-meta">
                        <span class="token-badge">📊 ${usage.totalTokens} tokens</span>
                    </div>
                `;
        }

        messageDiv.innerHTML = `
                <div class="message-avatar">${avatar}</div>
                <div class="message-content">
                    <div class="message-bubble">${escapeHtml(content)}</div>
                    ${metaHTML}
                </div>
            `;

        messagesDiv.appendChild(messageDiv);
        requestAnimationFrame(() => {
          messagesDiv.scrollTop = messagesDiv.scrollHeight;
        });
      }

      function showTypingIndicator() {
        const messagesDiv = document.getElementById("chatMessages");

        const typingDiv = document.createElement("div");
        typingDiv.className = "message assistant";
        typingDiv.id = "typingIndicator";
        typingDiv.innerHTML = `
                <div class="message-avatar">🤖</div>
                <div class="typing-indicator show">
                    <div class="typing-dots">
                        <span></span>
                        <span></span>
                        <span></span>
                    </div>
                </div>
            `;

        messagesDiv.appendChild(typingDiv);
        requestAnimationFrame(() => {
          messagesDiv.scrollTop = messagesDiv.scrollHeight;
        });
      }

      function hideTypingIndicator() {
        const typingIndicator = document.getElementById("typingIndicator");
        if (typingIndicator) {
          typingIndicator.remove();
        }
      }

      function showError(message) {
        const errorDiv = document.getElementById("errorMessage");
        errorDiv.textContent = "❌ " + message;
        errorDiv.classList.add("show");
      }

      function escapeHtml(text) {
        const div = document.createElement("div");
        div.textContent = text;
        return div.innerHTML.replace(/\n/g, "<br>");
      }
    </script>
  </body>
</html>

Paso 7: Prueba tu Aplicación de Chat

¡Es hora de probar nuestra aplicación de chat AI y ver la facturación en acción! Asegurémonos de que todo funcione de extremo a extremo.
Lo que estamos probando: Tendremos algunas conversaciones con la AI, verificaremos que los eventos de tokens lleguen a Dodo Payments y confirmaremos que los cálculos de facturación son correctos.
1

Inicia el servidor

Primero, asegúrate de que todo esté configurado:
  1. Verifica que tu .env archivo tenga todas las claves API del Paso 2
  2. Inicia el servidor de desarrollo:
npm run dev
Deberías ver:
🚀 Server running at http://localhost:3000
📊 Tracking event: ai_chat_usage
👤 Customer ID: {YOUR CUSTOMER_ID}
🔧 Environment: test_mode
¡El servidor está en funcionamiento! Es hora de chatear.
2

Abre la interfaz de chat

  1. Abre tu navegador
  2. Navega a http://localhost:3000
  3. Deberías ver la hermosa interfaz de chat
Asegúrate de actualizar el CUSTOMER_ID en server.ts con tu ID de cliente de prueba real del Paso 4.
3

Ten tu primera conversación

¡Probémoslo! Intenta estos mensajes:
  1. “¿Qué es la inteligencia artificial?”
  2. “¿Cómo funciona el aprendizaje automático?”
  3. “¿Puedes explicar las redes neuronales?”
¡Mira cómo se actualiza la visualización del uso de tokens después de cada respuesta!
Si ves a la AI respondiendo y los conteos de tokens apareciendo, ¡tu aplicación está funcionando!
4

Verifica tu panel de Dodo Payments

Ahora verifiquemos que los eventos están siendo recibidos:
  1. Abre tu panel de Dodo Payments
  2. Ve a Facturación por UsoMedidor de Uso de Tokens AI
  3. Haz clic en la pestaña Eventos
  4. Deberías ver tus eventos de chat listados
Qué buscar:
  • Nombres de eventos: ai_chat_usage
  • ID de cliente: Tu ID de cliente de prueba
Eventos del Medidor
¡Deberías ver un evento por cada mensaje que enviaste!
5

Verifica el conteo de tokens

Enviemos algunos mensajes más y verifiquemos si la agregación de tokens está funcionando:
  1. En tu medidor, ve a la pestaña Clientes
  2. Encuentra tu cliente de prueba
  3. Verifica la columna “Unidades Consumidas” - debería mostrar el total de tokens utilizados
Tokens de Cliente del Medidor
¡El medidor está sumando automáticamente todos los valores totalTokens!
6

Prueba el nivel gratuito

Usemos suficientes tokens para exceder el nivel gratuito:
  1. Ten varias más conversaciones (apunta a ~15,000+ tokens en total)
  2. Verifica tu pestaña Clientes en el panel del medidor nuevamente
  3. Ahora deberías ver:
    • Unidades Consumidas: 15,000+ tokens
    • Unidades Cobrables: 5,000 (10,000 tokens gratuitos aplicados)
    • Precio Total: ~$0.05
Prueba del Nivel Gratuito
¡Éxito! Tu facturación basada en el uso está funcionando perfectamente. Los clientes serán cobrados automáticamente según su consumo real de tokens.

Solución de Problemas

Problemas comunes y sus soluciones:
Causas posibles:
  • El nombre del evento no coincide exactamente con la configuración del medidor
  • El ID de cliente no existe en tu cuenta
  • La clave API es inválida o ha expirado
  • Problemas de conectividad de red
Soluciones:
  1. Verifica que el nombre del evento coincida exactamente con la configuración del medidor (sensible a mayúsculas y minúsculas: ai_chat_usage)
  2. Verifica que el ID de cliente exista en el panel de Dodo Payments
  3. Prueba la clave API con una llamada API simple
  4. Revisa los registros del servidor en busca de mensajes de error
Causas posibles:
  • El modelo no devuelve información de uso
  • Versión del SDK incorrecta
Soluciones:
  1. Prueba si el modelo devuelve uso:
const response = await generateText({...});
console.log('Usage:', response.usage);
  1. Actualiza a la última versión del SDK de Blueprints: npm install @dodopayments/ingestion-blueprints@latest
Causas posibles:
  • Clave API incorrecta para el entorno
  • Espacios o comillas adicionales en el archivo .env
Soluciones:
  • Asegúrate de que la clave de prueba comience con test_, la clave en vivo comience con live_
  • Elimina cualquier comilla alrededor de las claves en el archivo .env
  • Genera una nueva clave si es necesario
¿Necesitas ayuda?

¡Felicidades! Has Construido una Aplicación de Chat AI

Ahora tienes una aplicación de chat AI completamente funcional con seguimiento automático del uso de tokens y facturación impulsada por Dodo Payments. 🎉

Aprende Más