# Claude Message Threads API : guide des fils

> Les fils de messages de l'API Claude : l'en-tête bêta, les requêtes create et continue, les champs à renvoyer, l'expiration et le 404.

- Canonical HTML: https://omniakey.com/fr/blog/claude-message-threads-api-guide
- Markdown: https://omniakey.com/fr/blog/claude-message-threads-api-guide.md
- Published: 2026-11-04 (updated 2026-11-04)
- Author: Kiki, COO at OmniaKey
- Language: fr
- Category: API setup
- Reading time: 9 min
- All posts: https://omniakey.com/blog/llms.txt

---

L'API Claude Message Threads permet d'envoyer une longue conversation une seule fois, puis uniquement les nouveaux messages à chaque tour suivant. Ajoutez `"thread": {"type": "create"}` à la première requête Messages et l'en-tête bêta `message-threads-2026-08-12` : l'API garde la conversation en mémoire et la requête suivante envoie moins de contenu (page Message threads d'Anthropic, 4 novembre 2026).

C'est une bêta sur tous les modèles. 17 identifiants de modèle peuvent l'utiliser, dont [Claude Opus 5.5](https://omniakey.com/fr/claude-opus-5-5), que le code ci-dessous appelle. L'en-tête bêta accompagne chaque requête d'un fil.

## Ce qu'un fil économise

Sans fil, chaque tour transporte tout l'historique : le prompt système, les définitions d'outils, chaque message précédent et chaque résultat d'outil. Un fil range cette conversation, réponse de Claude comprise, sous l'`id` de la réponse, et une requête continue n'envoie que ce qui s'est passé depuis (page Message threads, 4 novembre 2026). Moins de contenu à chaque tour.

Le cache de prompt aide la même conversation autrement. Un succès de cache rend l'entrée répétée moins chère : sur Opus 5.5, 0,20 USD par million de tokens contre 4 USD pour une entrée neuve (page des tarifs d'Anthropic, 4 novembre 2026). La requête transporte quand même cette entrée. Le fil réduit ce que vous envoyez ; le cache réduit le prix de ce qui se répète. Les longues sessions gagnent aux deux, et [réduire la consommation de tokens de Claude Code](https://omniakey.com/fr/blog/reduce-claude-code-token-usage) couvre le côté contexte.

Les fils ne changent ni les tarifs ni les limites de débit (page Message threads, 4 novembre 2026). Les tarifs du moment sont sur [tarifs](https://omniakey.com/fr/pricing).

Le cache reste à votre charge. Envoyez un `cache_control` au niveau supérieur de chaque requête et l'API l'applique au dernier bloc cachable des `messages` de cette requête. La limite de quatre points d'arrêt est une règle du cache de prompt à l'échelle de la plateforme, et le cache automatique en occupe un (page du cache de prompt d'Anthropic, 4 novembre 2026). Répartissez-les ainsi :

1. le `cache_control` au niveau supérieur, un point dans chaque requête du fil ;
2. un sur `system`, envoyé avec la requête create ;
3. un sur `tools`, aussi à la création ;
4. un sur le message le plus récent.

Les points d'arrêt posés sur des messages déjà stockés sortent de ce budget, puisqu'une requête continue n'envoie que les nouveaux messages. Une fois envoyé, un point d'arrêt reste où il est. Quand vous renvoyez une conversation, retirez les points des messages antérieurs et gardez-en un sur le dernier bloc (page Message threads, 4 novembre 2026).

## Créer le premier tour, puis continuer

Trois étapes :

1. Placez votre clé Anthropic dans `ANTHROPIC_API_KEY`.
2. Envoyez la conversation complète, avec `system` et `tools` si vous les utilisez, plus `"thread": {"type": "create"}`.
3. Envoyez seulement les messages depuis la dernière réponse, plus `"thread": {"type": "continue", "previous_message_id": "<previous id>"}`, et laissez `system` et `tools` de côté.

Chaque requête porte l'en-tête bêta et `anthropic-version: 2026-10-21`, la version actuelle (page des versions d'Anthropic, 4 novembre 2026).

```bash
curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2026-10-21" \
  -H "anthropic-beta: message-threads-2026-08-12" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-5-5",
    "max_tokens": 1024,
    "system": "You are a careful backend reviewer.",
    "messages": [
      {"role": "user", "content": "Read this design and list the risks."}
    ],
    "thread": {"type": "create"}
  }'
```

Gardez l'`id` de cette réponse. La requête suivante n'envoie que le nouveau message :

```bash
PREVIOUS_ID="<id from the previous response>"

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2026-10-21" \
  -H "anthropic-beta: message-threads-2026-08-12" \
  -H "content-type: application/json" \
  -d @- <<JSON
{
  "model": "claude-opus-5-5",
  "max_tokens": 1024,
  "messages": [
    {"role": "user", "content": "Turn those risks into a checklist."}
  ],
  "thread": {"type": "continue", "previous_message_id": "$PREVIOUS_ID"}
}
JSON
```

Conservez l'`id` le plus récent de chaque réponse : un fil ne prend que des ajouts, chaque `id` de réponse se continue une seule fois, et la requête suivante doit utiliser le dernier (page Message threads, 4 novembre 2026).

S'il vous faut un autre moyen d'obtenir une clé API, OmniaKey vend un accès à l'API Claude avec les mêmes identifiants de modèle, donc le corps de la requête ne change pas. Les fils sont une bêta côté Anthropic : avant d'en dépendre en production, vérifiez que le relais que vous utilisez laisse passer le champ `thread` tel quel.

Le SDK Python suit les id pour vous. Créez un assistant avec `client.beta.messages.thread(...)`, qui ne fait que préparer l'appel, puis envoyez chaque tour avec `thread.send()`. L'assistant ajoute l'en-tête bêta, crée au premier tour, continue avec les seuls nouveaux messages et renvoie une fois toute la conversation dans une nouvelle requête create quand une requête continue donne `thread_not_found`, `thread_already_continued` ou `thread_continue_in_flight` (page Message threads, 4 novembre 2026).

```python
import anthropic

client = anthropic.Anthropic()  # lit ANTHROPIC_API_KEY

# L'assistant n'envoie encore rien ; il garde les champs réutilisés à chaque tour.
thread = client.beta.messages.thread(
    model="claude-opus-5-5",
    max_tokens=1024,
    system="You are a careful backend reviewer.",
)

first = thread.send({"role": "user", "content": "Read this design and list the risks."})
print(first.id, first.stop_reason)

second = thread.send({"role": "user", "content": "Turn those risks into a checklist."})
print(second.id)  # la prochaine fois, reprendre depuis cet id
```

Nous n'avons pas exécuté ces requêtes contre l'API d'Anthropic ; la forme vient de la page Message threads d'Anthropic. Pour le streaming, `thread.stream(...)` et `stream.get_final_message()` donnent le même déroulé, et `thread.previous_message_id` renvoie l'id quand vous préférez le suivre vous-même.

## Ce qu'il faut renvoyer, et ce qu'il ne faut jamais renvoyer

Envoyez les champs fixes avec les mêmes valeurs à chaque requête, `system` et `tools` seulement dans la requête create, et laissez les champs libres changer d'un tour à l'autre.

|Groupe|Champs|Règle|
|-|-|-|
|Create uniquement|`system`, `tools`|Seulement dans la requête create ; envoyer l'un ou l'autre dans une requête continue, même à `null`, renvoie 400.|
|Fixes|`model`, `tool_choice`, `thinking`, `mcp_servers` hormis le jeton d'autorisation de chaque serveur, `context_management`, `output_config`, les `skills` de `container`, le `cache_control` de niveau supérieur et l'ensemble des valeurs d'`anthropic-beta`|Même valeur à chaque fois. Une valeur différente renvoie 400 et nomme le champ qui diffère.|
|Libres|`max_tokens`, `stop_sequences`, `stream`, `metadata`, `service_tier` et les champs sans nom|Modifiables à volonté.|

Le 400 d'un champ fixe modifié porte `thread_fingerprint_mismatch`, et le message liste les champs qui diffèrent. Pour changer l'une de ces valeurs, ouvrez un nouveau fil avec la conversation complète et la nouvelle valeur.

Si `previous_message_id` manque, la requête continue renvoie 400 avec un message dans le corps mais aucun `error_code` ; ajouter `system` ou `tools` produit le même effet. Une requête continue doit porter exactement les messages depuis la dernière réponse.

`mcp_servers` est fixe, mais les URL des serveurs et les jetons d'autorisation ne vivent que dans votre requête : envoyez donc la liste dans chaque requête qui utilise MCP ; un jeton peut changer entre deux requêtes. L'`id` du conteneur ne vit que dans votre requête lui aussi, alors envoyez `container` à chaque fois (page Message threads, 4 novembre 2026).

Le repli côté serveur se décide à la création : envoyez `fallbacks` dans chaque requête du fil ou dans aucune. La valeur peut changer entre les tours, mais ajouter ou retirer le champ renvoie `thread_fingerprint_mismatch`.

## Expiration, renvoi et le 404

Un fil expire 5 minutes après sa dernière requête, et l'API le supprime au plus tard 1 heure après sa dernière utilisation. Chaque réponse stockée relance les 5 minutes. Les fils ne relèvent pas de la conservation nulle des données : la conversation, le prompt système et les outils restent en mémoire, chiffrés, et ne sont jamais écrits sur un stockage durable (page Message threads, 4 novembre 2026).

Aucun champ de la réponse ne dit si l'API a stocké un tour, ni en create ni en continue. Vous l'apprenez à la requête continue suivante : votre application reste la source de vérité et garde sa propre copie de chaque message (page Message threads, 4 novembre 2026).

Quand une requête continue renvoie 404 `thread_not_found`, envoyez la conversation complète dans une nouvelle requête create et reprenez depuis l'`id` de cette réponse. L'API renvoie le même 404 dans tous ces cas :

- le fil a expiré ;
- le tour précédent a été servi puis abandonné, par exemple un appel d'outil coupé par `max_tokens` ;
- un modèle de repli a écrit la réponse précédente ;
- la réponse précédente est encore en cours de génération ;
- la requête vient d'une autre organisation, d'un autre espace de travail, d'un autre utilisateur ou d'une autre clé d'espace de travail ;
- les nouveaux messages apportent du contenu absent de la conversation stockée, comme la première image d'une conversation qui n'en avait aucune.

Renvoyer la conversation complète est toujours sûr et répare chacun de ces cas.

Le streaming ajoute une règle : ne reprenez depuis l'`id` de la réponse qu'après `message_stop`, car une requête continue envoyée plus tôt peut renvoyer 404. Si le flux d'une requête continue s'interrompt avant `message_stop`, renvoyez la même requête continue, et renvoyez tout si cela donne `thread_already_continued` ou `thread_continue_in_flight`. L'assistant du SDK laisse le flux interrompu à votre retry.

Trois autres cas ont leur propre chemin :

- `pause_turn` : reprenez depuis l'`id` de cette réponse avec `"messages": []`. Si cela donne 404, renvoyez tout en incluant la réponse en pause.
- `stop_reason: "refusal"` : ouvrez un nouveau fil sans le tour qui l'a provoqué ; l'API détient peut-être déjà le tour refusé.
- une entrée `fallback_message` dans `usage.iterations`, ou dans le dernier `message_delta` d'un flux, signale une réponse de repli : renvoyez tout.

## Erreurs

Les cinq erreurs de fil reviennent avant que le modèle tourne : la requête ne consomme pas de tokens et le fil garde son délai. `error.type` vaut `invalid_request_error` pour les 400 et `not_found_error` pour le 404 (page Message threads, 4 novembre 2026).

- **404, `thread_not_found`** : l'API ne peut pas continuer ce fil. Envoyez la conversation complète dans une nouvelle requête create.
- **400, `thread_fingerprint_mismatch`** : un champ fixe a changé par rapport à la valeur stockée avec le fil. Gardez-le identique ou ouvrez un nouveau fil.
- **400, `thread_already_continued`** : cet `id` de réponse a déjà servi une fois. Reprenez depuis l'`id` le plus récent, et renvoyez tout si vous ne l'avez jamais reçu.
- **400, `thread_continue_in_flight`** : un autre continue sur le même `id` tourne encore, souvent votre essai précédent. Laissez-le finir ou renvoyez tout.
- **400, `thread_unsupported_request`** : la requête utilise une fonction ou un réglage d'organisation que les fils ne prennent pas en charge. `error.details.unsupported` nomme l'un de `context_management`, `cache_control`, `fallbacks`, `hipaa` ou `inference_hooks` ; cette liste peut s'allonger, donc si une valeur vous est inconnue, envoyez la conversation complète sans `thread`.

Message Batches refuse le champ `thread` (un élément de lot qui le porte échoue avec `invalid_request_error`), et le comptage de tokens comme la compaction renvoient 400 ; idem pour l'édition de contexte autre que `clear_thinking_20251015` avec `keep: "all"`. Les organisations prêtes pour HIPAA et celles qui activent Inference hooks sont exclues. Lister, lire et supprimer un fil n'existent pas dans l'API.

## Questions fréquentes

### Qu'est-ce que l'API Claude Message Threads ?

Une fonction bêta de l'API Messages qui stocke une conversation du côté d'Anthropic pour que les tours suivants n'envoient que les nouveaux messages. L'en-tête bêta est `message-threads-2026-08-12`, et chaque requête ajoute un objet `thread` dont `type` vaut `create` ou `continue`.

### Les fils fonctionnent-ils avec le cache de prompt ?

Oui. Un fil ne met pas votre prompt en cache à votre place : envoyez un `cache_control` au niveau supérieur de chaque requête et tenez-vous à quatre points d'arrêt. Les points posés sur les messages stockés ne comptent pas ; celui du niveau supérieur et ceux sur `system` ou `tools` comptent.

### Puis-je changer de modèle au milieu d'un fil ?

Un changement de modèle demande un nouveau fil. `model` est un champ fixe : une autre valeur renvoie 400 `thread_fingerprint_mismatch`. Ouvrez un nouveau fil avec la conversation complète et le nouveau modèle.

### Pourquoi une requête continue renvoie-t-elle 400 sans error\_code ?

Il manque `previous_message_id`, ou la requête contient `system` ou `tools`, même à `null`. Ces 400 portent un message et omettent `error_code` : lisez le texte.

### Combien de temps dure un fil, et que se passe-t-il à l'expiration ?

Un fil expire 5 minutes après sa dernière requête et est supprimé au plus tard 1 heure après sa dernière utilisation. Ensuite, une requête continue renvoie 404 `thread_not_found` ; envoyez la conversation complète dans une nouvelle requête create et reprenez depuis son `id`.

## Sources vérifiées

- [Anthropic : message threads](https://platform.claude.com/docs/en/build-with-claude/message-threads)
- [Anthropic : cache de prompt](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)
- [Anthropic : tarifs de l'API Claude](https://platform.claude.com/docs/en/about-claude/pricing)
- [Anthropic : versions de l'API](https://platform.claude.com/docs/en/api/versioning)
