> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Collecte et analyse de données avec la plateforme ElevenAgents dans Next.js

> **Note**
>
> **Tutoriel** · Suppose que vous avez suivi le [guide de démarrage rapide d’ElevenAgents](/docs/fr/eleven-agents/quickstart) et configuré un projet Next.js.

## Introduction

Dans ce tutoriel, vous apprendrez à créer un agent vocal qui collecte des informations auprès de l’utilisateur au fil de la conversation, puis analyse et extrait les données de manière structurée avant de les envoyer à votre application via le webhook post-appel.

## Prérequis

* Un compte ElevenLabs avec une [clé API](https://elevenlabs.io/app/settings/api-keys).
* Node.js v18 ou une version ultérieure installé sur votre machine.

## Configuration

### Créer un projet Next.js

Nous vous recommandons d’utiliser notre [modèle de plateforme ElevenAgents v0.dev](https://v0.dev/community/nextjs-5TN93pl3bRS) comme point de départ pour votre application. Ce modèle est une application Next.js prête pour la production, avec l’agent ElevenLabs déjà intégré.

### Configurer la plateforme ElevenAgents

Suivez notre [guide Next.js](/docs/fr/eleven-agents/guides/quickstarts/next-js) pour les étapes d’installation et de configuration. Revenez ensuite ici pour créer les fonctionnalités avancées.

## Configuration de l’agent

#### Se connecter à ElevenLabs

Accédez à [elevenlabs.io](https://elevenlabs.io/app/sign-up) et connectez-vous à votre compte.

#### Créer un agent

Accédez à [Agents Platform > Agents](https://elevenlabs.io/app/agents/agents) et
créez un agent à partir du modèle vierge.

#### Définir le premier message

Définissez le premier message et indiquez la variable dynamique de la plateforme.

```txt
Hi {{user_name}}, I'm Jess from the ElevenLabs team. I'm here to help you design your very own ElevenLabs agent! To kick things off, let me know what kind of agent you're looking to create. For example, do you want a support agent, to help your users answer questions, or a sales agent to sell your products, or just a friend to chat with?
```

#### Définir le prompt système

Définissez le prompt système. Vous pouvez également y inclure des variables dynamiques.

```txt
You are Jess, a helpful agent helping {{user_name}} to design their very own ElevenLabs agent. The design process involves the following steps:

"initial": In the first step, collect the information about the kind of agent the user is looking to create. Summarize the user's needs back to them and ask if they are ready to continue to the next step. Only once they confirm proceed to the next step.
"training": Tell the user to create the agent's knowledge base by uploading documents, or submitting URLs to public websites with information that should be available to the agent. Wait patiently without talking to the user. Only when the user confirms that they've provided everything then proceed to the next step.
"voice": Tell the user to describe the voice they want their agent to have. For example: "A professional, strong spoken female voice with a slight British accent." Repeat the description of their voice back to them and ask if they are ready to continue to the next step. Only once they confirm proceed to the next step.
"email": Tell the user that we've collected all necessary information to create their ElevenLabs agent and ask them to provide their email address to get notified when the agent is ready.

Always call the `set_ui_state` tool when moving between steps!
```

#### Configurer les outils client

Configurez l’outil client suivant pour naviguer entre les étapes :

* Nom : `set_ui_state`
  * Description : Utilisez cet outil côté client pour naviguer entre les différents états de l’interface utilisateur.
  * Attendre la réponse : `true`
  * Délai d’expiration de la réponse (secondes) : 1
  * Paramètres :
    * Type de données : string
    * Identifiant : step
    * Obligatoire : true
    * Type de valeur : LLM Prompt
    * Description : Étape vers laquelle naviguer dans l’interface utilisateur. Utilisez uniquement les étapes définies dans le prompt système.

#### Définir la voix de votre agent

Accédez à l’onglet `Voice` et définissez la voix de votre agent. Vous trouverez une liste de voix recommandées pour la plateforme ElevenAgents dans la [documentation de conception de voix conversationnelles](/docs/fr/eleven-agents/customization/voice/best-practices/conversational-voice-design#voices).

#### Définir les critères d’évaluation

Accédez à l’onglet `Analysis` et ajoutez un critère d’évaluation.

* Nom : `all_data_provided`
  * Prompt : Évaluez si l’utilisateur a fourni une description de l’agent qu’il souhaite générer, ainsi qu’une description de la voix que cet agent doit avoir.

#### Configurer la collecte de données

Vous pouvez utiliser l’analyse post-appel pour extraire des données de la conversation. Dans l’onglet `Analysis`, sous `Data Collection`, ajoutez les éléments suivants :

* Identifiant : `voice_description`
  * `data-type` : `String`
  * Description : À partir de la description de la voix souhaitée par l’utilisateur pour l’agent, générez une description concise de la voix incluant l’âge, l’accent, le ton et le caractère, si ces informations sont disponibles.
* Identifiant : `agent_description`
  * `data-type` : `String`
  * Description : À partir de la description de l’agent que l’utilisateur souhaite concevoir, générez un prompt pouvant servir à entraîner un modèle à agir comme cet agent.

#### Configurer le webhook post-appel

Les [webhooks post-appel](https://elevenlabs.io/docs/eleven-agents/workflows/post-call-webhooks) vous avertissent lorsqu’un appel se termine et que les étapes d’analyse et d’extraction de données sont terminées.

Dans cet exemple, le webhook post-appel effectue notamment les étapes suivantes :

1. Créer une conception de voix personnalisée à partir de `voice_description`.
2. Créer un agent ElevenLabs pour les utilisateurs à partir de la valeur `agent_description` qu’ils ont fournie.
3. Récupérer les documents de la base de connaissances depuis l’état de la conversation stocké dans Redis et associer la base de connaissances à l’agent.
4. Envoyer un email à l’utilisateur pour l’informer que son agent ElevenLabs personnalisé est prêt à converser.

Lors d’une exécution locale, vous aurez besoin d’un outil tel que [ngrok](https://ngrok.com/) pour exposer votre serveur local à Internet.

```bash
ngrok http 3000
```

Accédez aux [paramètres de la plateforme ElevenAgents](https://elevenlabs.io/app/agents/settings), puis sous `Post-Call Webhook`, créez un webhook et collez votre URL ngrok : `https://<your-url>.ngrok-free.app/api/convai-webhook`.

Après avoir enregistré le webhook, vous recevrez un secret de webhook. Conservez-le de manière sécurisée, car vous devrez ensuite le définir dans votre fichier `.env`.

## Intégrer les fonctionnalités avancées

### Configurer une base de données Redis pour stocker l’état de la conversation

Dans cet exemple, nous utilisons Redis pour stocker l’état de la conversation. Cela nous permet de récupérer les documents de la base de connaissances à partir de l’état de la conversation une fois l’appel terminé.

Si vous déployez sur Vercel, vous pouvez configurer l’intégration [Upstash for Redis](https://vercel.com/marketplace/upstash). Vous pouvez aussi créer un [compte Upstash](https://upstash.com/) gratuit et une base de données.

### Configurer Resend pour l’envoi des emails post-appel

Dans cet exemple, nous utilisons Resend pour envoyer l’email post-appel à l’utilisateur. Pour cela, créez un [compte Resend](https://resend.com/) gratuit et configurez une clé API.

### Définir les variables d’environnement

À la racine de votre projet, créez un fichier `.env` et ajoutez les variables suivantes :

```bash
ELEVENLABS_CONVAI_WEBHOOK_SECRET=
ELEVENLABS_API_KEY=
ELEVENLABS_AGENT_ID=

# Resend
RESEND_API_KEY=
RESEND_FROM_EMAIL=

# Upstash Redis
KV_URL=
KV_REST_API_READ_ONLY_TOKEN=
REDIS_URL=
KV_REST_API_TOKEN=
KV_REST_API_URL=
```

### Configurer la sécurité et l’authentification

Pour sécuriser votre agent ElevenLabs, vous devez activer l’authentification dans l’onglet `Security` de la configuration de l’agent.

Une fois l’authentification activée, vous devrez créer une URL signée dans un environnement serveur sécurisé afin de lancer une conversation avec l’agent. Dans Next.js, vous pouvez le faire en configurant une nouvelle route API.

**`./app/api/signed-url/route.ts`**

```tsx ./app/api/signed-url/route.ts
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { NextResponse } from "next/server";

export async function GET() {
  const agentId = process.env.ELEVENLABS_AGENT_ID;
  if (!agentId) {
    throw Error("ELEVENLABS_AGENT_ID is not set");
  }
  try {
    const elevenlabs = new ElevenLabsClient();
    const response = await elevenlabs.conversationalAi.conversations.getSignedUrl({
      agentId,
    });
    return NextResponse.json({ signedUrl: response.signedUrl });
  } catch (error) {
    console.error("Error:", error);
    return NextResponse.json({ error: "Failed to get signed URL" }, { status: 500 });
  }
}
```

### Démarrer la session de conversation

Pour démarrer la conversation, appelez d’abord votre route API afin d’obtenir l’URL signée, puis utilisez le hook `useConversation` pour configurer la session de conversation.

**`./page.tsx`**

```tsx ./page.tsx {1,4,20-25,31-46}
import { useConversation } from "@elevenlabs/react";

async function getSignedUrl(): Promise<string> {
  const response = await fetch("/api/signed-url");
  if (!response.ok) {
    throw Error("Failed to get signed url");
  }
  const data = await response.json();
  return data.signedUrl;
}

export default function Home() {
  // ...
  const [currentStep, setCurrentStep] = useState<
    "initial" | "training" | "voice" | "email" | "ready"
  >("initial");
  const [conversationId, setConversationId] = useState("");
  const [userName, setUserName] = useState("");

  const conversation = useConversation({
    onConnect: () => console.log("Connected"),
    onDisconnect: () => console.log("Disconnected"),
    onMessage: (message: string) => console.log("Message:", message),
    onError: (error: Error) => console.error("Error:", error),
  });

  const startConversation = useCallback(async () => {
    try {
      // Request microphone permission
      await navigator.mediaDevices.getUserMedia({ audio: true });
      // Start the conversation with your agent
      const signedUrl = await getSignedUrl();
      const convId = await conversation.startSession({
        signedUrl,
        dynamicVariables: {
          user_name: userName,
        },
        clientTools: {
          set_ui_state: ({ step }: { step: string }): string => {
            // Allow agent to navigate the UI.
            setCurrentStep(step as "initial" | "training" | "voice" | "email" | "ready");
            return `Navigated to ${step}`;
          },
        },
      });
      setConversationId(convId);
      console.log("Conversation ID:", convId);
    } catch (error) {
      console.error("Failed to start conversation:", error);
    }
  }, [conversation, userName]);
  const stopConversation = useCallback(async () => {
    await conversation.endSession();
  }, [conversation]);
  // ...
}
```

### Outil client et variables dynamiques

Lors de la configuration de l’agent, vous avez enregistré l’outil client `set_ui_state` afin de permettre à l’agent de naviguer entre les différents états de l’interface utilisateur. Pour tout relier, vous devez transmettre l’implémentation de l’outil client aux options de `conversation.startSession`.

C’est également ici que vous pouvez transmettre les variables dynamiques à la conversation.

**`./page.tsx`**

```tsx ./page.tsx {3-5,7-11}
const convId = await conversation.startSession({
  signedUrl,
  dynamicVariables: {
    user_name: userName,
  },
  clientTools: {
    set_ui_state: ({ step }: { step: string }): string => {
      // Allow agent to navigate the UI.
      setCurrentStep(step as "initial" | "training" | "voice" | "email" | "ready");
      return `Navigated to ${step}`;
    },
  },
});
```

### Importer des documents dans la base de connaissances

À l’étape `Training`, l’agent demandera à l’utilisateur d’importer des documents ou de soumettre des URL de sites web publics contenant des informations qui devront être accessibles à son agent. Vous pouvez ici tirer parti de la nouvelle fonction `after` de [Next.js 15](https://nextjs.org/docs/app/api-reference/functions/after) pour autoriser l’importation de documents en arrière-plan.

Créez une nouvelle action serveur `upload` afin de gérer la création de la base de connaissances lors de la soumission du formulaire. Une fois tous les documents de la base de connaissances créés, stockez l’ID de conversation et les ID de la base de connaissances dans la base de données Redis.

**`./app/actions/upload.ts`**

```tsx ./app/actions/upload.ts {26,32,44,56-60}
"use server";

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { Redis } from "@upstash/redis";
import { redirect } from "next/navigation";
import { after } from "next/server";

// Initialize Redis
const redis = Redis.fromEnv();

const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});

export async function uploadFormData(formData: FormData) {
  const knowledgeBase: Array<{
    id: string;
    type: "file" | "url";
    name: string;
  }> = [];
  const files = formData.getAll("file-upload") as File[];
  const email = formData.get("email-input");
  const urls = formData.getAll("url-input");
  const conversationId = formData.get("conversation-id");

  after(async () => {
    // Upload files as background job
    // Create knowledge base entries
    // Loop through files and create knowledge base entries
    for (const file of files) {
      if (file.size > 0) {
        const response = await elevenlabs.conversationalAi.knowledgeBase.documents.createFromFile({
          file,
        });
        if (response.id) {
          knowledgeBase.push({
            id: response.id,
            type: "file",
            name: file.name,
          });
        }
      }
    }
    // Append all urls
    for (const url of urls) {
      const response = await elevenlabs.conversationalAi.knowledgeBase.documents.createFromUrl({
        url: url as string,
      });
      if (response.id) {
        knowledgeBase.push({
          id: response.id,
          type: "url",
          name: `url for ${conversationId}`,
        });
      }
    }

    // Store knowledge base IDs and conversation ID in database.
    const redisRes = await redis.set(
      conversationId as string,
      JSON.stringify({ email, knowledgeBase })
    );
    console.log({ redisRes });
  });

  redirect("/success");
}
```

## Gérer le webhook post-appel

Le [webhook post-appel](/docs/fr/eleven-agents/workflows/post-call-webhooks) est déclenché lorsqu’un appel se termine et que les étapes d’analyse et d’extraction de données sont terminées.

Voici les différentes étapes effectuées :

1. Vérifier le secret du webhook et construire la charge utile du webhook.
2. Créer une conception de voix personnalisée à partir de `voice_description`.
3. Créer un agent ElevenLabs pour les utilisateurs à partir de la valeur `agent_description` qu’ils ont fournie.
4. Récupérer les documents de la base de connaissances depuis l’état de la conversation stocké dans Redis et associer la base de connaissances à l’agent.
5. Envoyer un email à l’utilisateur pour l’informer que son agent ElevenLabs personnalisé est prêt à converser.

**`./app/api/convai-webhook/route.ts`**

```ts ./app/api/convai-webhook/route.ts
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { Redis } from "@upstash/redis";
import crypto from "crypto";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { Resend } from "resend";

import { EmailTemplate } from "@/components/email/post-call-webhook-email";

// Initialize Redis
const redis = Redis.fromEnv();
// Initialize Resend
const resend = new Resend(process.env.RESEND_API_KEY);

const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});

export async function GET() {
  return NextResponse.json({ status: "webhook listening" }, { status: 200 });
}

export async function POST(req: NextRequest) {
  const secret = process.env.ELEVENLABS_CONVAI_WEBHOOK_SECRET; // Add this to your env variables
  const { event, error } = await constructWebhookEvent(req, secret);
  if (error) {
    return NextResponse.json({ error: error }, { status: 401 });
  }

  if (event.type === "post_call_transcription") {
    const { conversation_id, analysis, agent_id } = event.data;

    if (
      agent_id === process.env.ELEVENLABS_AGENT_ID &&
      analysis.evaluation_criteria_results.all_data_provided?.result === "success" &&
      analysis.data_collection_results.voice_description?.value
    ) {
      try {
        // Design the voice
        const voicePreview = await elevenlabs.textToVoice.createPreviews({
          voiceDescription: analysis.data_collection_results.voice_description.value,
          text: "The night air carried whispers of betrayal, thick as London fog. I adjusted my cufflinks - after all, even spies must maintain appearances, especially when the game is afoot.",
        });
        const voice = await elevenlabs.textToVoice.createVoiceFromPreview({
          voiceName: `voice-${conversation_id}`,
          voiceDescription: `Voice for ${conversation_id}`,
          generatedVoiceId: voicePreview.previews[0].generatedVoiceId,
        });

        // Get the knowledge base from redis
        const redisRes = await getRedisDataWithRetry(conversation_id);
        if (!redisRes) throw new Error("Conversation data not found!");
        // Handle agent creation
        const agent = await elevenlabs.conversationalAi.agents.create({
          name: `Agent for ${conversation_id}`,
          conversationConfig: {
            tts: { voiceId: voice.voiceId },
            agent: {
              prompt: {
                prompt:
                  analysis.data_collection_results.agent_description?.value ??
                  "You are a helpful assistant.",
                knowledgeBase: redisRes.knowledgeBase,
              },
              firstMessage: "Hello, how can I help you today?",
            },
          },
        });
        console.log("Agent created", { agent: agent.agentId });
        // Send email to user
        console.log("Sending email to", redisRes.email);
        await resend.emails.send({
          from: process.env.RESEND_FROM_EMAIL!,
          to: redisRes.email,
          subject: "Your ElevenLabs agent is ready to chat!",
          react: EmailTemplate({ agentId: agent.agentId }),
        });
      } catch (error) {
        console.error(error);
        return NextResponse.json({ error }, { status: 500 });
      }
    }
  }

  return NextResponse.json({ received: true }, { status: 200 });
}

const constructWebhookEvent = async (req: NextRequest, secret?: string) => {
  const body = await req.text();
  const signatureHeader = req.headers.get("ElevenLabs-Signature");

  return await elevenlabs.webhooks.constructEvent(body, signatureHeader, secret);
};

async function getRedisDataWithRetry(
  conversationId: string,
  maxRetries = 5
): Promise<{
  email: string;
  knowledgeBase: Array<{
    id: string;
    type: "file" | "url";
    name: string;
  }>;
} | null> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const data = await redis.get(conversationId);
      return data as any;
    } catch (error) {
      if (attempt === maxRetries) throw error;
      console.log(`Redis get attempt ${attempt} failed, retrying...`);
      await new Promise((resolve) => setTimeout(resolve, 1000));
    }
  }
  return null;
}
```

Examinons chaque étape en détail.

### Vérifier le secret du webhook et construire la charge utile du webhook

Lorsque la requête webhook est reçue, nous vérifions d’abord le secret du webhook et construisons la charge utile du webhook.

**`./app/api/convai-webhook/route.ts`**

```ts ./app/api/convai-webhook/route.ts
// ...

export async function POST(req: NextRequest) {
  const secret = process.env.ELEVENLABS_CONVAI_WEBHOOK_SECRET;
  const { event, error } = await constructWebhookEvent(req, secret);
  // ...
}

// ...
const constructWebhookEvent = async (req: NextRequest, secret?: string) => {
  const body = await req.text();
  const signatureHeader = req.headers.get("ElevenLabs-Signature");

  return await elevenlabs.webhooks.constructEvent(body, signatureHeader, secret);
};

async function getRedisDataWithRetry(
  conversationId: string,
  maxRetries = 5
): Promise<{
  email: string;
  knowledgeBase: Array<{
    id: string;
    type: "file" | "url";
    name: string;
  }>;
} | null> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const data = await redis.get(conversationId);
      return data as any;
    } catch (error) {
      if (attempt === maxRetries) throw error;
      console.log(`Redis get attempt ${attempt} failed, retrying...`);
      await new Promise((resolve) => setTimeout(resolve, 1000));
    }
  }
  return null;
}
```

### Créer une conception de voix personnalisée à partir de `voice_description`

À l’aide de la valeur `voice_description` de la charge utile du webhook, nous créons une conception de voix personnalisée.

**`./app/api/convai-webhook/route.ts`**

```ts ./app/api/convai-webhook/route.ts {5}
// ...

// Design the voice
const voicePreview = await elevenlabs.textToVoice.createPreviews({
  voiceDescription: analysis.data_collection_results.voice_description.value,
  text: "The night air carried whispers of betrayal, thick as London fog. I adjusted my cufflinks - after all, even spies must maintain appearances, especially when the game is afoot.",
});
const voice = await elevenlabs.textToVoice.createVoiceFromPreview({
  voiceName: `voice-${conversation_id}`,
  voiceDescription: `Voice for ${conversation_id}`,
  generatedVoiceId: voicePreview.previews[0].generatedVoiceId,
});

// ...
```

### Récupérer les documents de la base de connaissances depuis l’état de la conversation stocké dans Redis

L’importation des documents peut prendre plus de temps que l’analyse des données du webhook. Nous devons donc interroger l’état de la conversation dans Redis jusqu’à ce que les documents soient importés.

**`./app/api/convai-webhook/route.ts`**

```ts ./app/api/convai-webhook/route.ts
// ...

// Get the knowledge base from redis
const redisRes = await getRedisDataWithRetry(conversation_id);
if (!redisRes) throw new Error("Conversation data not found!");
// ...

async function getRedisDataWithRetry(
  conversationId: string,
  maxRetries = 5
): Promise<{
  email: string;
  knowledgeBase: Array<{
    id: string;
    type: "file" | "url";
    name: string;
  }>;
} | null> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const data = await redis.get(conversationId);
      return data as any;
    } catch (error) {
      if (attempt === maxRetries) throw error;
      console.log(`Redis get attempt ${attempt} failed, retrying...`);
      await new Promise((resolve) => setTimeout(resolve, 1000));
    }
  }
  return null;
}
```

### Créer un agent ElevenLabs pour les utilisateurs à partir de la valeur `agent_description` qu’ils ont fournie

Créez l’agent ElevenLabs pour l’utilisateur à partir de la valeur `agent_description` qu’il a fournie, puis associez à l’agent la conception de voix et la base de connaissances nouvellement créées.

**`./app/api/convai-webhook/route.ts`**

```ts ./app/api/convai-webhook/route.ts {7,11}
// ...

// Handle agent creation
const agent = await elevenlabs.conversationalAi.agents.create({
  name: `Agent for ${conversationId}`,
  conversationConfig: {
    tts: { voiceId: voice.voiceId },
    agent: {
      prompt: {
        prompt:
          analysis.data_collection_results.agent_description?.value ??
          "You are a helpful assistant.",
        knowledgeBase: redisRes.knowledgeBase,
      },
      firstMessage: "Hello, how can I help you today?",
    },
  },
});
console.log("Agent created", { agent: agent.agentId });

// ...
```

### Envoyer un email à l’utilisateur pour l’informer que son agent ElevenLabs personnalisé est prêt à converser

Une fois l’agent créé, vous pouvez envoyer un email à l’utilisateur pour l’informer que son agent ElevenLabs personnalisé est prêt à converser.

**`./app/api/convai-webhook/route.ts`**

```ts ./app/api/convai-webhook/route.ts
import { Resend } from "resend";

import { EmailTemplate } from "@/components/email/post-call-webhook-email";

// ...

// Send email to user
console.log("Sending email to", redisRes.email);
await resend.emails.send({
  from: process.env.RESEND_FROM_EMAIL!,
  to: redisRes.email,
  subject: "Your ElevenLabs agent is ready to chat!",
  react: EmailTemplate({ agentId: agent.agentId }),
});

// ...
```

Vous pouvez utiliser [new.email](https://new.email/), un outil pratique de l’équipe Resend, pour concevoir vos modèles d’email de façon intuitive. Lorsque le modèle vous convient, créez un composant et ajoutez l’ID de l’agent en tant que prop.

**`./components/email/post-call-webhook-email.tsx`**

```tsx ./components/email/post-call-webhook-email.tsx {14}
import {
  Body,
  Button,
  Container,
  Head,
  Html,
  Section,
  Text,
  Tailwind,
} from "@react-email/components";
import * as React from "react";

const EmailTemplate = (props: any) => {
  const { agentId } = props;
  return (
    <Html>
      <Head />
      <Tailwind>
        <Body className="bg-[#151516] font-sans">
          <Container className="mx-auto my-[40px] max-w-[600px] rounded-[8px] bg-[#0a1929] p-[20px]">
            {/* Top Section */}
            <Section className="mb-[32px] mt-[32px] text-center">
              <Text className="m-0 text-[28px] font-bold text-[#9c27b0]">
                Your ElevenLabs agent is ready to chat!
              </Text>
            </Section>

            {/* Content Area with Icon */}
            <Section className="mb-[32px] text-center">
              {/* Circle Icon with Checkmark */}
              <div className="mx-auto mb-[24px] flex h-[80px] w-[80px] items-center justify-center rounded-full bg-gradient-to-r from-[#9c27b0] to-[#3f51b5]">
                <div className="text-[40px] text-white">✓</div>
              </div>

              {/* Descriptive Text */}
              <Text className="mb-[24px] text-[18px] text-white">
                Your ElevenLabs agent is ready to chat!
              </Text>
            </Section>

            {/* Call to Action Button */}
            <Section className="mb-[32px] text-center">
              <Button
                href={`https://elevenlabs.io/app/talk-to?agent_id=${agentId}`}
                className="box-border rounded-[8px] bg-[#9c27b0] px-[40px] py-[20px] text-[24px] font-bold text-white no-underline"
              >
                Chat now!
              </Button>
            </Section>

            {/* Footer */}
            <Section className="mt-[40px] border-t border-[#2d3748] pt-[20px] text-center">
              <Text className="m-0 text-[14px] text-white">
                Powered by{" "}
                <a
                  href="https://elevenlabs.io/conversational-ai"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="underline transition-colors hover:text-gray-400"
                >
                  ElevenLabs Agents
                </a>
              </Text>
            </Section>
          </Container>
        </Body>
      </Tailwind>
    </Html>
  );
};

export { EmailTemplate };
```

## Exécuter l’application

Pour exécuter l’application localement de bout en bout, démarrez d’abord le serveur de développement Next.js, puis exécutez le tunnel ngrok dans un terminal distinct afin d’exposer le gestionnaire de webhook à Internet.

* Terminal 1 :
  * Exécutez `pnpm dev` pour démarrer le serveur de développement Next.js.

```bash
pnpm dev
```

* Terminal 2 :
  * Exécutez `ngrok http 3000` pour exposer le gestionnaire de webhook à Internet.

```bash
ngrok http 3000
```

Ouvrez maintenant [http://localhost:3000](http://localhost:3000) et commencez à concevoir votre agent ElevenLabs personnalisé, avec votre propre voix.

## Prochaines étapes

#### [ElevenAgents](/docs/fr/eleven-agents/quickstart)

Découvrez la plateforme ElevenAgents complète pour créer et déployer des agents vocaux.

#### [Analyse des agents](/docs/fr/eleven-agents/customization/agent-analysis)

Consultez les données de conversation, l’évaluation de la réussite et les indicateurs de performance des agents.