# Détections de texte

> Classez un texte brut comme rédigé par IA, mixte ou humain avec POST /text/detections. Champs de la requête et de la réponse, positions des segments, limites et facturation.

Source : https://fileverity.com/fr/docs/text-detections

`POST /text/detections` lance une vérification de texte. Elle classe un texte brut avec `fvdoc-3-text` et renvoie les passages rédigés par IA. Elle est synchrone : le résultat se trouve dans la réponse.

Les exemples lisent le texte dans un fichier : enregistrez donc d’abord un passage de 100 mots ou plus sous le nom `essay.txt`. Le [Démarrage rapide](https://fileverity.com/fr/docs/quickstart.md#text) contient une commande qui écrit un exemple.

**Requête: cURL**

```bash
curl https://api.fileverity.com/v1/text/detections \
  -H "Authorization: Bearer $FILEVERITY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6b9d1c1e-3b0f-4c0a-9a53-2d1c9d6b7e11" \
  -d "$(jq -Rs '{text: ., language: "en"}' essay.txt)"
```

**Requête: JavaScript**

```javascript
import { readFile } from "node:fs/promises";
import { randomUUID } from "node:crypto";

const response = await fetch("https://api.fileverity.com/v1/text/detections", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.FILEVERITY_API_KEY,
    "Content-Type": "application/json",
    "Idempotency-Key": randomUUID(),
  },
  body: JSON.stringify({ text: await readFile("essay.txt", "utf8"), language: "en" }),
});
const detection = await response.json();
```

**Requête: Python**

```python
import os
import uuid
import requests

response = requests.post(
    "https://api.fileverity.com/v1/text/detections",
    headers={
        "Authorization": "Bearer " + os.environ["FILEVERITY_API_KEY"],
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={"text": open("essay.txt", encoding="utf-8").read(), "language": "en"},
)
detection = response.json()
```

## Corps de la requête

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `text` | chaîne | Oui | Texte brut d’au moins 100 mots et d’au plus 100 000 caractères. |
| `model` | chaîne | Non | Valeur par défaut : `fvdoc-3-text`. Accepte l’ID du modèle ou son ID d’instantané `fvdoc-3-text-2026-11-03`. |
| `language` | chaîne ou null | Non | Code ISO 639-1 : `en`, `fr`, `de`, `es`, `zh`. Détectée automatiquement si le champ est omis. |

Les champs inconnus sont rejetés avec `invalid_parameter`. Lors du contrôle du minimum de 100 mots, environ deux caractères chinois comptent pour un mot.

## Réponse

**200 OK**

```json
{
  "id": "tdet_8Hk2pQ4vN9sL1xR7cW3mY6zB",
  "object": "text.detection",
  "created": 1793664000,
  "model": "fvdoc-3-text-2026-11-03",
  "livemode": true,
  "language": "en",
  "verdict": "mixed",
  "score": 0.97,
  "ai_fraction": 0.41,
  "segments": [
    {
      "start": 212,
      "end": 433,
      "score": 0.97
    },
    {
      "start": 579,
      "end": 790,
      "score": 0.93
    }
  ],
  "usage": {
    "characters": 1412,
    "free_characters": 0,
    "billed_units": 2
  }
}
```

| Champ | Type | Description |
| --- | --- | --- |
| `id` | chaîne | ID de détection, avec le préfixe `tdet_`. |
| `object` | chaîne | Toujours `text.detection`. |
| `created` | entier | Horodatage Unix. |
| `model` | chaîne | Instantané qui a produit le résultat. |
| `livemode` | booléen | `false` pour les clés de test. |
| `language` | chaîne | La langue utilisée : celle que vous avez envoyée, ou celle qui a été détectée. |
| `verdict` | chaîne | `ai` : le texte semble entièrement rédigé par IA. `mixed` : des passages rédigés par IA au sein d’un texte humain. `human` : aucun passage rédigé par IA trouvé. |
| `score` | nombre | De 0 à 1. Score du modèle pour le passage qui ressemble le plus à un texte rédigé par IA. |
| `ai_fraction` | nombre | De 0 à 1. Part du texte évalué contenue dans des segments rédigés par IA. |
| `segments` | tableau | Les passages rédigés par IA. Chacun comporte `start`, `end` (exclu) et `score`. |
| `usage` | objet | `characters` évalués, `free_characters` couverts par votre démarrage gratuit et `billed_units` effectivement facturés après les caractères gratuits. |

> **Remarque.** La détection de texte renvoie une estimation statistique, et non une preuve de l’identité de l’auteur. Les limites des segments sont approximatives. Considérez-la comme un élément parmi d’autres d’un examen humain et ne vous appuyez pas uniquement dessus pour prendre une décision concernant une personne.

## Positions des segments

`start` et `end` sont des positions dans le texte que vous avez envoyé, comptées en points de code Unicode, et non en octets ni en unités UTF-16. Les limites des segments sont approximatives et peuvent inclure des phrases adjacentes. Les chaînes JavaScript sont indexées en UTF-16 : découpez donc d’abord le texte en points de code :

**Extraire un segment: JavaScript**

```javascript
const points = Array.from(text);
for (const { start, end } of detection.segments) {
  console.log(points.slice(start, end).join(""));
}
```

**Extraire un segment: Python**

```python
for segment in detection["segments"]:
    print(text[segment["start"]:segment["end"]])
```

Les chaînes Python sont déjà indexées par point de code.

## Facturation

- Le texte est facturé 0,14 $ US par tranche de 1 000 caractères, comptés en points de code Unicode. Chaque requête est arrondie à l’unité supérieure, avec un minimum d’une unité.
- Les caractères de texte de votre démarrage gratuit sont utilisés en premier et indiqués dans `usage.free_characters`. `usage.billed_units` est le nombre d’unités facturées une fois ces caractères déduits : le coût est donc `billed_units` multiplié par 0,14 $ US. Exemple : 1 412 caractères sans caractères gratuits restants représentent 2 unités, soit 0,28 $ US.
- Les requêtes rejetées avant l’évaluation ne sont pas facturées : paramètres non valides, texte trop court ou trop long, langues non prises en charge, etc. Une vérification qui échoue au sein du service (`service_unavailable`) est libérée et n’est pas facturée.
- Un solde insuffisant renvoie `insufficient_balance` (402).

## Ce qui est conservé

Le texte est évalué puis supprimé. Il n’est jamais conservé et ne peut donc pas être récupéré ultérieurement.

Fileverity conserve le résultat, sans le texte (verdict, scores, positions des passages et utilisation), pendant 7 jours, afin que la Console puisse l’afficher et que l’utilisation puisse être facturée et auditée. Une nouvelle tentative avec la même `Idempotency-Key` reçoit le résultat enregistré pendant 24 heures. Les détections de texte sont synchrones : elles n’apparaissent pas dans `GET /analyses` et n’envoient pas d’événements webhook. Les clés de test n’enregistrent rien. Voir [Conservation des données et sécurité](https://fileverity.com/fr/docs/security.md).

## Erreurs

| Code | Statut | Cause |
| --- | --- | --- |
| `text_too_short` | 400 | Moins de 100 mots. |
| `text_too_long` | 413 | Plus de 100 000 caractères. Divisez le texte en plusieurs requêtes. |
| `unsupported_language` | 400 | La langue n’est pas prise en charge ou n’a pas pu être détectée. |
| `unsupported_media_type` | 415 | Le corps n’est pas envoyé en `application/json`. |
| `invalid_json` | 400 | Le corps n’est pas un objet JSON. |
| `missing_parameter` | 400 | Le champ `text` est absent. |
| `invalid_parameter` | 400 | Un champ a un type incorrect, un champ inconnu a été envoyé ou la `Idempotency-Key` n’est pas valide. |
| `model_not_found` | 404 | Le `model` est inconnu. |
| `insufficient_balance` | 402 | Le solde ne permet pas de couvrir la requête. |
| `spend_limit_reached` | 402 | La clé a atteint sa limite de dépense mensuelle. |
| `idempotency_mismatch`, `idempotency_in_progress` | 409 | La `Idempotency-Key` a été utilisée avec un corps différent, ou sa première requête est encore en cours. |
| `service_unavailable`, `analysis_failed` | 503, 502 | Le service de détection est temporairement indisponible ou surchargé. Aucune facturation ; réessayez. `service_unavailable` s’accompagne d’un en-tête `retry-after`. |

> **Remarque.** Envoyez une `Idempotency-Key` pour qu’une nouvelle tentative après un délai dépassé ne soit pas facturée deux fois. Voir [Idempotence](https://fileverity.com/fr/docs/idempotency.md).

