# Voix et décompte

## Ce qui est compté

- Une conversation **ouverte** compte pour **1**, même si l'avatar ne parle pas.
- **Chaque tranche de 5 réponses parlées** compte pour une conversation de plus (réglable par déploiement, voir votre contrat).
- Une **réponse parlée** = un tour (`turn`) qui a reçu au moins une voix. Les morceaux d'une même réponse, envoyés avec le même `turn`, ne comptent qu'**une fois**.
- Les réponses **écrites** ne comptent pas.
- L'affichage de l'avatar (`GET /v1/avatars/…`) et la reprise d'une conversation (`resume`) ne comptent pas.

| Réponses parlées dans la conversation | Conversations décomptées |
| --- | --- |
| 0 à 5 | 1 |
| 6 à 10 | 2 |
| 11 à 15 | 3 |

## Les tours

Chaque question posée à `/messages` ouvre un **nouveau tour**. Son numéro arrive dans l'événement `done` :

```text
data: {"type": "done", "text": "Oui, nous avons trois SUV.", "turn": 3,
       "voice": {"allowed": true, "reason": null, "units": 1, "spoken": 2}}
```

Redonnez ce `turn` à **chaque morceau** envoyé à `/speech` pour cette réponse :

```json
{ "text": "Oui, nous avons trois SUV.", "lang": "fr", "turn": 3 }
```

- Sans `turn` : le dernier tour de la conversation (`0` avant la première question, par exemple pour un message d'accueil).
- Un tour pas encore donné par `/messages` est refusé : `400 invalid_request`.
- Un tour reçoit **1 500 caractères de voix au plus**, tous morceaux compris (environ 1 min 30). Un morceau qui ferait dépasser est refusé (`409`, `X-Twimi-Voice-Reason: reponse`) et rien n'est dit : découpez vos réponses en conséquence.
- Un morceau fait **2 000 caractères au plus** ; les liens et le balisage Markdown sont retirés avant lecture.

La réponse de `/speech` porte trois en-têtes pour suivre le décompte :

| En-tête | Valeur |
| --- | --- |
| `X-Twimi-Chars` | caractères lus |
| `X-Twimi-Turn` | tour compté |
| `X-Twimi-Units` | conversations décomptées pour cette conversation |

## Quand la voix n'est pas disponible

L'écrit continue **toujours**. Le champ `voice` (à l'ouverture et dans `done`) dit si la voix est disponible ; sinon, affichez la réponse seulement et cachez le micro.

| `voice.reason` | Cause | Ce qui se passe |
| --- | --- | --- |
| `forfait` | forfait du mois atteint | les nouvelles conversations s'ouvrent en écrit seul ; une conversation en cours ne peut pas entamer une nouvelle tranche de réponses parlées |
| `conversation` | plafond de réponses parlées de la conversation (si votre déploiement en a un) | la conversation continue par écrit |
| `fusible` | trafic anormal (plus de 3 fois le volume habituel du jour) | voix suspendue par précaution ; Twimi vous contacte pour la rétablir |
| `formule` | formule Avatar SDK | la voix est la vôtre : pas de voix Twimi |
| `reponse` | sur `/speech` : la réponse dépasserait 1 500 caractères de voix | ce morceau n'est pas dit |

Sur `/speech` et `/transcriptions`, un refus prend la forme `409 voice_limit_reached`, avec l'en-tête `X-Twimi-Voice-Reason`. La suite d'une réponse déjà commencée reste acceptée, dans la limite de 1 500 caractères.

:::info{title="Jamais de dépassement facturé"}

Au-delà du forfait, rien n'est bloqué et aucun dépassement n'est facturé : l'avatar passe à l'écrit. Twimi est alerté à **80 % et à 100 %** du forfait ; l'envoi de ces alertes par e-mail à votre contact arrive prochainement.

:::

## Suivre sa consommation

`GET /v1/usage?period=AAAA-MM`, avec la **clé secrète** :

```json
{
  "period": "2026-10",
  "deployment": { "id": "dep_…", "client": "concession", "formula": "agent" },
  "conversations": { "opened": 1102, "counted": 1288 },
  "limit": 2000
}
```

`opened` : conversations ouvertes ; `counted` : conversations décomptées du forfait. D'où `counted` ≥ `opened`.

## Transcription

`POST /v1/conversations/{id}/transcriptions` transcrit la question orale du visiteur.

- Corps `multipart/form-data` : `audio` (webm, ogg, mp4, m4a, wav ou mp3 ; **5 Mo au plus**) et `lang`, facultatif.
- Une question orale dure **30 secondes au plus** : coupez l'enregistrement au-delà.
- **Le son n'est jamais conservé.**

```bash
curl -s -X POST $TWIMI/conversations/conv_9xk2…/transcriptions \
  -H "Authorization: Bearer $JETON" \
  -F audio=@question.webm -F lang=fr
```
