Passer au contenu principal
Laissez Sentra écrire votre code d’intégration pour vous.
Utilisez notre assistant IA dans VS Code, Cursor ou Windsurf pour générer du code SDK/API, du code d’intégration LLM Blueprint, des webhooks et bien plus encore - il vous suffit de décrire ce que vous voulez.
Essayez Sentra : intégration propulsée par l’IA →
Dans ce tutoriel, vous allez construire une application de chat AI avec facturation automatique basée sur l’utilisation. Nous allons créer tout à partir de zéro : le compteur de facturation, la configuration du produit, et le code de l’application qui alimente les conversations et suit l’utilisation des tokens en temps réel.
Ce tutoriel fournit une application complète fonctionnelle avec backend et frontend. L’application de chat utilise Gemini AI de Google et suit automatiquement l’utilisation des jetons sans avoir besoin de comptage manuel.
À la fin de ce tutoriel, vous aurez une application de chat fonctionnelle qui :
  • Alimente des conversations AI utilisant Google Gemini (AI SDK)
  • Suit automatiquement l’utilisation des tokens (pas de code manuel)
  • Facture les clients en fonction de la consommation réelle de tokens
  • Inclut une belle interface de chat
Démo du chat IA

Ce que nous construisons

Commençons par comprendre notre service de chat AI :
  • Service : Chat alimenté par AI utilisant Google Gemini (AI SDK)
  • Modèle de tarification : Pay-per-token (0,01 $ par 1 000 tokens)
  • Niveau gratuit : 10 000 tokens gratuits par client par mois
  • Fonctionnalités : Historique des conversations, suivi automatique des tokens
Avant de commencer, assurez-vous d’avoir :

Étape 1 : Créez votre compteur d’utilisation

Nous allons commencer par créer un compteur dans votre tableau de bord Dodo Payments qui suivra l’utilisation des tokens AI.
Ce que nous construisons : Un compteur nommé “AI Token Usage Meter” qui totalise tous les jetons consommés dans les conversations de chat.
1

Open the Meters section

  1. Connectez-vous à votre tableau de bord Dodo Payments
  2. Cliquez sur Produits dans la barre latérale gauche
  3. Cliquez sur Compteurs
  4. Cliquez sur le bouton Créer un compteur
Créer un compteur
Vous devriez voir un formulaire où nous configurerons le suivi de nos jetons.
2

Fill in the basic meter information

Maintenant, nous allons saisir les détails spécifiques pour notre service de chat IA :Nom du compteurAI Token Usage MeterDescriptionTracks token consumption from AI chat conversations using AI SDKNom de l’événementai_chat_usage
Le nom d’événement ai_chat_usage doit correspondre exactement à ce que nous enverrons plus tard depuis notre code d’application. Les noms d’événements sont sensibles à la casse !
3

Configure how we count tokens

Configurez l’agrégation (comment le compteur compte nos événements) :Type d’agrégation : Sélectionnez Somme dans le menu déroulantAgrégat sur : Type → totalTokensUnité de mesure : Type → tokens
Nous utilisons « Somme » car nous voulons additionner tous les jetons consommés dans plusieurs messages de chat. Le SDK envoie automatiquement totalTokens dans chaque événement.
4

Create your meter

  1. Vérifiez que tous vos paramètres correspondent aux valeurs ci-dessus
  2. Cliquez sur Créer un compteur
Configuration du compteur
Compteur créé ! Votre “AI Token Usage Meter” est maintenant prêt à commencer à compter les jetons. Ensuite, nous le connecterons à un produit de facturation.

Étape 2 : Obtenez vos clés API

Avant de construire l’application, rassemblons les clés API dont nous aurons besoin.
1

Get Dodo Payments API Key

  1. Dans votre tableau de bord Dodo Payments, allez dans DéveloppeursClés API
  2. Cliquez sur Créer une clé API
  3. Copiez la clé API - elle ressemblera à test_abc123...
Enregistrez cette clé API - nous l’ajouterons à notre fichier .env plus tard.
2

Get Google AI API Key

  1. Rendez-vous sur aistudio.google.com
  2. Cliquez sur Obtenir une clé API
  3. Créez une nouvelle clé API ou utilisez-en une existante
  4. Copiez la clé
Gardez cette clé en lieu sûr - nous l’ajouterons aussi à notre fichier .env.

Étape 3 : Créez votre produit de facturation

Maintenant, nous devons créer un produit qui définit notre tarification (0,01 $ par 1 000 tokens avec 10 000 tokens gratuits). Cela connecte notre compteur à la facturation réelle.
Ce que nous construisons : Un produit appelé “AI Chat Service” qui facture en fonction de la consommation de jetons avec un généreux palier gratuit.
1

Navigate to Products

  1. Dans votre tableau de bord Dodo Payments, cliquez sur Produits dans la barre latérale gauche
  2. Cliquez sur Créer un produit
  3. Sélectionnez Usage-Based comme type de produit
Cela indique à Dodo Payments que la facturation sera basée sur l’utilisation du compteur, et non sur un abonnement fixe.
2

Enter product details

Remplissez les détails requis :Nom du produit : → AI Chat ServiceDescription : → AI-powered chat service with automatic token-based billingImage du produit : Téléchargez une image pertinente
Ils apparaîtront sur les factures clients, alors rendez-les clairs et professionnels.
3

Connect your meter

Avant de connecter votre compteur, assurez-vous d’avoir sélectionné Facturation basée sur l’utilisation comme type de prix pour votre produit.De plus, définissez le Prix fixe sur 0 afin de garantir que les clients ne sont facturés qu’en fonction de leur utilisation, sans frais de base.Maintenant, liez le compteur que vous venez de créer :
  1. Faites défiler vers le bas jusqu’à la section Compteur associé
  2. Cliquez sur Ajouter des compteurs
  3. Dans le menu déroulant, sélectionnez “Compteur d’utilisation des tokens AI” (celui que vous avez créé plus tôt)
  4. Confirmez qu’il apparaît dans la configuration de votre produit
Votre compteur est maintenant connecté avec succès à ce produit.
4

Set your pricing

Voici où nous définissons notre modèle économique :Prix par unité : saisissez 0.00001 (ce qui correspond à 0,01 pour1000jetonsou0,00001pour 1 000 jetons ou 0,00001 par jeton)Seuil gratuit : saisissez 10000 (les clients bénéficient de 10 000 jetons gratuits par mois)
Tarification du produit
Fonctionnement de la facturation : si un client utilise 25 000 jetons dans un mois, il sera facturé pour 15 000 jetons (25 000 - 10 000 gratuits) = 15 000 × 0,00001 =0,15= 0,15
5

Save your product

  1. Passez en revue tous vos paramètres :
    • Nom : AI Chat Service
    • Compteur : AI Token Usage Meter
    • Prix : 0,01 $ pour 1 000 jetons
    • Palier gratuit : 10 000 jetons
  2. Cliquez sur Enregistrer les modifications
Produit créé ! Votre facturation est maintenant configurée. Les clients seront automatiquement facturés en fonction de leur utilisation de jetons.

Étape 4 : Effectuez un achat test

Avant de commencer à construire l’application, créons un client test en effectuant un achat.
1

Get your payment link

  1. Dans votre tableau de bord Dodo Payments, allez dans Produits
  2. Trouvez votre produit « AI Chat Service »
  3. Cliquez sur le bouton Partager à côté de votre produit
  4. Copiez le lien de paiement qui apparaît
2

Complete a test purchase

  1. Ouvrez le lien de paiement dans un nouvel onglet de navigateur
  2. Saisissez des informations de paiement de test et finalisez l’achat
Après un paiement réussi, vous obtiendrez un identifiant client que nous utiliserons dans notre code d’application.
3

Find your customer ID

  1. Revenez dans votre tableau de bord Dodo Payments
  2. Accédez à Ventes -> Clients dans la barre latérale gauche
  3. Trouvez le client que vous venez de créer (avec l’e-mail de test)
  4. Copiez l’identifiant client - il ressemblera à cus_123
Enregistrez cet identifiant client - nous l’utiliserons lors des tests de notre application de chat.

Étape 5 : Construisez l’application de chat

Maintenant que notre configuration de facturation est complète et qu’un client test a été créé. Construisons l’application de chat AI avec suivi automatique des tokens.
1

Set up your project

Créez un nouveau répertoire et initialisez le projet :
mkdir ai-chat-app
cd ai-chat-app
npm init -y
2

Install dependencies

Installez les packages dont nous avons besoin :
npm install express ai @ai-sdk/google @dodopayments/ingestion-blueprints dotenv
npm install --save-dev typescript @types/express @types/node tsx
3

Configure TypeScript

Créez 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"]
}
Mettez à jour package.json pour ajouter le type de module et les scripts :
package.json
{
  "type": "module",
  "scripts": {
    "dev": "tsx src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}
4

Create project structure

Créez les dossiers et fichiers :
mkdir src public
5

Set up environment variables

Créez un fichier .env à la racine de votre projet :
.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
Remplacez les valeurs factices par vos clés API réelles de l’étape 2.
6

Create the backend server

Créez src/server.ts et copiez ce code serveur complet :
Voici le serveur de chat AI complet avec facturation intégrée :
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}`);
});

Étape 6 : Ajoutez l’interface de chat

Maintenant, ajoutons une magnifique interface de chat avec tout l’historique des conversations ! Créez 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>

Étape 7 : Testez votre application de chat

Il est temps de tester notre application de chat AI et de voir la facturation en action ! Assurons-nous que tout fonctionne de bout en bout.
Ce que nous testons : Nous aurons quelques conversations avec l’IA, vérifierons que les événements de jetons parviennent à Dodo Payments et confirmerons que les calculs de facturation sont corrects.
1

Start the server

Tout d’abord, assurez-vous que tout est configuré :
  1. Vérifiez que votre fichier .env contient toutes les clés API de l’étape 2
  2. Démarrez le serveur de développement :
npm run dev
Vous devriez voir :
🚀 Server running at http://localhost:3000
📊 Tracking event: ai_chat_usage
👤 Customer ID: {YOUR CUSTOMER_ID}
🔧 Environment: test_mode
Le serveur fonctionne ! Il est temps de discuter.
2

Open the chat interface

  1. Ouvrez votre navigateur
  2. Rendez-vous sur http://localhost:3000
  3. Vous devriez voir la superbe interface de chat
Assurez-vous de mettre à jour CUSTOMER_ID dans server.ts avec votre identifiant client de test réel de l’étape 4.
3

Have your first conversation

Testons-le ! Essayez ces messages :
  1. “Qu’est-ce que l’intelligence artificielle ?”
  2. “Comment fonctionne l’apprentissage automatique ?”
  3. “Pouvez-vous expliquer les réseaux neuronaux ?”
Regardez l’affichage de l’utilisation des tokens se mettre à jour après chaque réponse !
Si vous voyez l’IA répondre et les comptes de jetons apparaître, votre application fonctionne !
4

Check your Dodo Payments dashboard

Vérifions maintenant que les événements sont reçus :
  1. Ouvrez votre tableau de bord Dodo Payments
  2. Allez à Facturation d’utilisationCompteur d’utilisation des tokens AI
  3. Cliquez sur l’onglet Événements
  4. Vous devriez voir vos événements de chat listés
Ce qu’il faut vérifier :
  • Noms d’événements : ai_chat_usage
  • Identifiant client : votre identifiant client de test
Événements du compteur
Vous devriez voir un événement pour chaque message que vous avez envoyé !
5

Verify token counting

Envoyons quelques messages de plus et vérifions si l’agrégation des jetons fonctionne :
  1. Dans votre compteur, allez à l’onglet Clients
  2. Trouvez votre client test
  3. Vérifiez la colonne “Unités consommées” - elle devrait afficher le total des tokens utilisés
Jetons clients du compteur
Le compteur additionne automatiquement toutes les valeurs totalTokens !
6

Test the free tier

Utilisons suffisamment de jetons pour dépasser le palier gratuit :
  1. Ayez plusieurs autres conversations (visez ~15 000+ tokens au total)
  2. Vérifiez à nouveau votre onglet Clients dans le tableau de bord du compteur
  3. Vous devriez maintenant voir :
    • Unités consommées : 15 000+ tokens
    • Unités facturables : 5 000 (10 000 tokens gratuits appliqués)
    • Prix total : ~0,05 $
Test du palier gratuit
Succès ! Votre facturation basée sur l’utilisation fonctionne parfaitement. Les clients seront automatiquement facturés en fonction de leur consommation réelle de jetons.

Dépannage

Problèmes courants et leurs solutions :
Causes possibles :
  • Le nom de l’événement ne correspond pas exactement à la configuration du compteur
  • L’identifiant client n’existe pas dans votre compte
  • La clé API est invalide ou expirée
  • Problèmes de connectivité réseau
Solutions :
  1. Vérifiez que le nom de l’événement correspond exactement à la configuration du compteur (sensible à la casse : ai_chat_usage)
  2. Vérifiez que l’identifiant client existe dans le tableau de bord Dodo Payments
  3. Testez la clé API avec un appel API simple
  4. Consultez les journaux du serveur pour les messages d’erreur
Causes possibles :
  • Le modèle ne renvoie pas d’informations d’utilisation
  • Version du SDK incorrecte
Solutions :
  1. Testez si le modèle renvoie l’utilisation :
const response = await generateText({...});
console.log('Usage:', response.usage);
  1. Mettez à jour vers le dernier SDK Blueprints : npm install @dodopayments/ingestion-blueprints@latest
Causes possibles :
  • Mauvaise clé API pour l’environnement
  • Espaces ou guillemets en trop dans le fichier .env
Solutions :
  • Assurez-vous que la clé de test commence par test_, la clé en production par live_
  • Supprimez les guillemets autour des clés dans le fichier .env
  • Générez une nouvelle clé si nécessaire
Besoin d’aide ?

Félicitations ! Vous avez construit une application de chat AI

Vous avez maintenant une application de chat AI entièrement fonctionnelle avec suivi automatique de l’utilisation des tokens et facturation alimentée par Dodo Payments. 🎉

En savoir plus