# Démarrage rapide

Ce guide fait parler l'avatar depuis votre serveur, avec une **clé secrète** de test. Dans une page web, le principe est le même avec la clé publique (voir [Clés et jetons](/authentification)).

Il vous faut une clé `sk_test_…`, remise par Twimi à la création de votre déploiement. Gardez-la dans une variable d'environnement :

```bash
export TWIMI_KEY=sk_test_…
export TWIMI=https://api-dev.atwimi.com/v1
```

<Stepper>

1. **Vérifier la clé**

   `GET /v1/me` dit à quoi la clé donne accès : le client, l'avatar, la formule et les langues.

   <CodeTabs>

   ```bash
   curl -s $TWIMI/me -H "Authorization: Bearer $TWIMI_KEY"
   ```

   ```js
   const TWIMI = process.env.TWIMI;
   const res = await fetch(`${TWIMI}/me`, {
     headers: { Authorization: `Bearer ${process.env.TWIMI_KEY}` },
   });
   const { deployment } = await res.json();
   console.log(deployment.avatar, deployment.formula);
   ```

   ```python
   import os, requests
   TWIMI = os.environ["TWIMI"]
   r = requests.get(f"{TWIMI}/me", headers={"Authorization": f"Bearer {os.environ['TWIMI_KEY']}"})
   print(r.json()["deployment"])
   ```

   </CodeTabs>

1. **Ouvrir une conversation**

   À la **première action** du visiteur, pas au simple affichage : chaque ouverture est décomptée de votre forfait.

   <CodeTabs>

   ```bash
   curl -s -X POST $TWIMI/conversations \
     -H "Authorization: Bearer $TWIMI_KEY" \
     -H "Content-Type: application/json" \
     -d '{"lang": "fr"}'
   ```

   ```js
   const res = await fetch(`${TWIMI}/conversations`, {
     method: "POST",
     headers: {
       Authorization: `Bearer ${process.env.TWIMI_KEY}`,
       "Content-Type": "application/json",
     },
     body: JSON.stringify({ lang: "fr" }),
   });
   const conv = await res.json(); // { conversation_id, token, expires_at, voice, … }
   ```

   </CodeTabs>

   Vous recevez un `conversation_id` et un **jeton** valable 30 minutes. La suite se fait avec ce jeton, plus avec la clé.

1. **Poser une question**

   La réponse arrive **en flux** (`text/event-stream`) : affichez les morceaux `token` au fil de l'eau. L'événement `done` donne la réponse complète et le numéro du tour, `turn`.

   ```js
   const res = await fetch(`${TWIMI}/conversations/${conv.conversation_id}/messages`, {
     method: "POST",
     headers: { Authorization: `Bearer ${conv.token}`, "Content-Type": "application/json" },
     body: JSON.stringify({ message: "Vous avez des SUV ?", mode: "voice" }),
   });

   const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
   let tampon = "", fin = null;
   while (true) {
     const { value, done } = await reader.read();
     if (done) break;
     tampon += value;
     const lignes = tampon.split("\n");
     tampon = lignes.pop();
     for (const ligne of lignes) {
       if (!ligne.startsWith("data: ")) continue;
       const evt = JSON.parse(ligne.slice(6));
       if (evt.type === "token") process.stdout.write(evt.text);
       if (evt.type === "done") fin = evt;          // { text, products, turn, voice }
       if (evt.type === "error") throw new Error(evt.code);
     }
   }
   ```

   :::tip

   `EventSource` n'accepte pas les requêtes `POST` : lisez le flux avec `fetch`, comme ci-dessus.

   :::

1. **Faire parler l'avatar**

   Si `fin.voice.allowed` vaut `true`, envoyez la réponse à `/speech` **phrase par phrase**, avec le même `turn` pour chaque morceau : la première phrase se fait entendre pendant que la suivante se prépare, et la réponse ne compte qu'une fois.

   ```js
   const phrases = fin.text.match(/[^.!?]+[.!?]+/g) ?? [fin.text];
   for (const phrase of phrases) {
     const son = await fetch(`${TWIMI}/conversations/${conv.conversation_id}/speech`, {
       method: "POST",
       headers: { Authorization: `Bearer ${conv.token}`, "Content-Type": "application/json" },
       body: JSON.stringify({ text: phrase.trim(), lang: "fr", turn: fin.turn }),
     });
     if (son.status === 409) break;                 // voix indisponible : la suite par écrit
     const mp3 = await son.arrayBuffer();          // audio/mpeg, à jouer (SDK : face.play(son))
   }
   ```

1. **Garder la conversation en vie, puis la terminer**

   Avant 30 minutes, renouvelez le jeton avec `POST /conversations/{id}/token`. Une conversation dure **10 minutes au plus** depuis son ouverture : au-delà, `410 conversation_expired`, ouvrez-en une nouvelle. Quand le visiteur a fini, `POST /conversations/{id}/end` (facultatif).

</Stepper>

## Ensuite

- [Le cycle d'une conversation](/conversations) : reprise, renouvellement, durée.
- [Voix et décompte](/voix-et-decompte) : quand la voix est disponible, et ce qui est compté.
- [Erreurs et limites](/erreurs) : les codes à traiter dans votre intégration.
