---
title: Crédit de repli
url: https://platform.claude.com/docs/fr/build-with-claude/fallback-credit
description: Évitez de payer deux fois le coût de la mise en cache des prompts lorsque vous relancez une requête refusée sur un autre modèle.
---

Les caches de prompts sont propres à chaque modèle. Lorsqu'un modèle décline une requête et que vous la relancez sur un autre modèle, le préfixe de conversation déjà mis en cache pour le premier modèle doit être écrit de zéro dans le cache du nouveau modèle. Les écritures en cache coûtent plus cher que les lectures en cache. Le « fallback credit » (crédit de repli) supprime ce coût supplémentaire. Le refus transporte un jeton de crédit, vous renvoyez ce jeton lors de la nouvelle tentative, et celle-ci est facturée comme si la conversation s'était déroulée sur le nouveau modèle depuis le début.

Vous n'avez besoin de cette page que si vous construisez vous-même la nouvelle tentative : via HTTP brut ou avec une logique de relance personnalisée. Le [repli côté serveur](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback#server-side-fallback) et le [middleware du SDK](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback#client-side-fallback) appliquent automatiquement le crédit de repli. Si vous utilisez l'un ou l'autre, ignorez cette page.

[Refus et repli](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback) traite de la détection des refus et du choix d'une approche de repli. [Mise en cache des prompts](https://platform.claude.com/docs/fr/build-with-claude/prompt-caching) explique les lectures en cache et les écritures en cache si ces termes sont nouveaux pour vous.

## Le flux de base

<Steps>
  <Step title="Activez la fonctionnalité avec l'en-tête bêta">
    Envoyez la requête susceptible d'être refusée avec l'en-tête `anthropic-beta: fallback-credit-2026-07-01`. L'en-tête `server-side-fallback-2026-07-01` donne également accès aux mêmes champs, sauf sur Amazon Bedrock et Google Cloud, qui renvoient une erreur 400 pour cet en-tête. L'ancien en-tête `fallback-credit-2026-06-01` reste accepté et donne accès aux mêmes champs.
  </Step>

  <Step title="Lisez deux champs dans le refus">
    Lors d'un refus, `stop_details` inclut deux champs :

    * **`fallback_credit_token` :** une chaîne opaque qui représente le crédit.
    * **`fallback_has_prefill_claim` :** un booléen qui vous indique quelle forme de corps de requête utiliser pour la nouvelle tentative.

    Les deux valent `null` lorsqu'aucun crédit n'est disponible pour le refus.
  </Step>

  <Step title="Construisez la nouvelle tentative">
    Partez du corps de la requête refusée. Définissez `model` sur le modèle de repli et ajoutez le jeton en tant que paramètre de premier niveau `fallback_credit_token`. Choisissez la forme du corps dans le tableau suivant.
  </Step>

  <Step title="Envoyez la nouvelle tentative avec le même en-tête">
    Envoyez la nouvelle tentative avec le même en-tête bêta `fallback-credit-2026-07-01`. La nouvelle tentative a besoin de cet en-tête pour utiliser le jeton.
  </Step>
</Steps>

Le champ `fallback_has_prefill_claim` vous indique si la nouvelle tentative peut poursuivre la sortie partielle du modèle ayant refusé au lieu de repartir de zéro :

| `fallback_has_prefill_claim` | Corps de la nouvelle tentative                                                                                                                                                                                                                                                                                      |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `true`                       | Le corps de la requête refusée, inchangé, plus un message assistant ajouté à la fin dont le `content` reprend le `content` de la réponse refusée. Le modèle de la nouvelle tentative poursuit la réponse là où le modèle ayant refusé s'est arrêté, et les appels d'outils serveur terminés ne sont pas réexécutés. |
| `false`                      | Le corps de la requête refusée, inchangé.                                                                                                                                                                                                                                                                           |

## Exemple

L'exemple suivant effectue une requête susceptible d'être refusée et utilise le jeton de crédit lors d'une nouvelle tentative sur Claude Opus 4.8. Lorsqu'une tentative de relance est rejetée, l'exemple descend l'échelle de rejet : la séquence de formes de relance progressivement plus simples décrite dans [Lorsqu'une nouvelle tentative est rejetée](https://platform.claude.com/docs/fr/build-with-claude/fallback-credit#when-a-retry-is-rejected).

<CodeGroup>
  ```bash cURL
  # Requête initiale (peut être refusée)
  response=$(curl --fail-with-body -sS https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: fallback-credit-2026-07-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-fable-5",
      "max_tokens": 1024,
      "messages": [{"role": "user", "content": "Hello, Claude"}]
    }')

  # Un refus comporte un jeton de crédit à usage unique dans stop_details
  token=$(jq -r '.stop_details.fallback_credit_token // empty' <<<"${response}")

  if [[ -n "${token}" ]]; then
    # Réessayer sur le modèle de repli avec le jeton de crédit (même corps)
    response=$(curl --fail-with-body -sS https://api.anthropic.com/v1/messages \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "anthropic-beta: fallback-credit-2026-07-01" \
      -H "content-type: application/json" \
      -d "$(jq -n --arg token "${token}" '{
        model: "claude-opus-4-8",
        max_tokens: 1024,
        messages: [{"role": "user", "content": "Hello, Claude"}],
        fallback_credit_token: $token
      }')")
  fi

  # Voir les exemples du SDK pour l'échelle complète de gestion des refus.
  jq -c '{stop_reason, model}' <<<"${response}"
  ```

  ```bash CLI
  # Requête initiale (peut être refusée)
  response=$(ant beta:messages create \
    --model claude-fable-5 \
    --max-tokens 1024 \
    --message '{"role":"user","content":"Hello, Claude"}' \
    --beta fallback-credit-2026-07-01 \
    --format json)

  # Un refus comporte un jeton de crédit à usage unique dans stop_details
  token=$(jq -r '.stop_details.fallback_credit_token // empty' <<<"${response}")

  if [[ -n "${token}" ]]; then
    # Réessayer sur le modèle de repli avec le jeton de crédit
    response=$(ant beta:messages create \
      --model claude-opus-4-8 \
      --max-tokens 1024 \
      --message '{"role":"user","content":"Hello, Claude"}' \
      --fallback-credit-token "${token}" \
      --beta fallback-credit-2026-07-01 \
      --format json)
  fi

  # Voir les exemples du SDK pour l'échelle complète de gestion des refus.
  jq -c '{stop_reason, model}' <<<"${response}"
  ```

  ```python Python
  client = Anthropic()

  request = {
      "max_tokens": 1024,
      "messages": [{"role": "user", "content": "Hello, Claude"}],
  }


  def send(model: str, body: dict[str, object]) -> BetaMessage:
      return client.beta.messages.create(
          model=model, betas=["fallback-credit-2026-07-01"], **body
      )


  response = send("claude-fable-5", request)

  if (
      response.stop_reason == "refusal"
      and (details := response.stop_details)
      and (token := details.fallback_credit_token)
  ):
      exact_body = request | {"fallback_credit_token": token}
      # Privilégier la forme de continuation sauf si le claim vaut False
      if details.fallback_has_prefill_claim is not False:
          echoed = [block.model_dump() for block in response.content]
          match echoed:
              case [*_, {"type": "text"} as final_block]:
                  final_block["text"] = final_block["text"].rstrip()
          attempt = exact_body | {
              "messages": [
                  *request["messages"],
                  {"role": "assistant", "content": echoed},
              ]
          }
      else:
          attempt = exact_body

      try:
          response = send("claude-opus-4-8", attempt)
      except BadRequestError as error:
          if "redemption temporarily unavailable" in error.message:
              raise  # Transient: retry with the token within its five-minute window
          try:
              # Revenir au corps inchangé, toujours avec le jeton
              response = send("claude-opus-4-8", exact_body)
          except BadRequestError as retry_error:
              if "redemption temporarily unavailable" in retry_error.message:
                  raise  # Transient: retry with the token within its five-minute window
              # Le jeton lui-même a été rejeté : l'abandonner et réessayer sans.
              response = send("claude-opus-4-8", request)

  print(json.dumps({"stop_reason": response.stop_reason, "model": response.model}))
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const request: Anthropic.Beta.MessageCreateParamsNonStreaming = {
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello, Claude" }],
    betas: ["fallback-credit-2026-07-01"]
  };

  let response = await client.beta.messages.create(request);

  if (
    response.stop_reason === "refusal" &&
    response.stop_details?.type === "refusal" &&
    response.stop_details.fallback_credit_token
  ) {
    const { fallback_credit_token, fallback_has_prefill_claim } = response.stop_details;
    const fallbackModel = "claude-opus-4-8";

    const exactRetry: Anthropic.Beta.MessageCreateParamsNonStreaming = {
      ...request,
      model: fallbackModel,
      fallback_credit_token
    };

    // Forme la plus riche d'abord, dégradée à chaque rejet : la forme de
    // continuation (sauf si l'assertion est fausse), le corps inchangé portant
    // encore le jeton, et enfin l'abandon du jeton.
    let attempt = exactRetry;
    if (fallback_has_prefill_claim !== false) {
      const finalBlock = response.content.at(-1);
      const echoed: Anthropic.Beta.BetaContentBlockParam[] =
        finalBlock?.type === "text"
          ? [
              ...response.content.slice(0, -1),
              { ...finalBlock, text: finalBlock.text.trimEnd() }
            ]
          : response.content;
      attempt = {
        ...exactRetry,
        messages: [...request.messages, { role: "assistant", content: echoed }]
      };
    }

    try {
      response = await client.beta.messages.create(attempt);
    } catch (error) {
      // Ne dégrader que sur une erreur 400 liée à la forme. « redemption temporarily
      // unavailable » est transitoire : réessayez de la même manière dans la
      // fenêtre de cinq minutes du jeton à la place.
      if (
        !(error instanceof Anthropic.BadRequestError) ||
        error.message.includes("redemption temporarily unavailable")
      ) {
        throw error;
      }
      try {
        response = await client.beta.messages.create(exactRetry);
      } catch (retryError) {
        if (
          !(retryError instanceof Anthropic.BadRequestError) ||
          retryError.message.includes("redemption temporarily unavailable")
        ) {
          throw retryError;
        }
        response = await client.beta.messages.create({ ...request, model: fallbackModel });
      }
    }
  }

  const { stop_reason, model } = response;
  console.log(JSON.stringify({ stop_reason, model }));
  ```

  ```csharp C#
  var client = new AnthropicClient();
  const string beta = "fallback-credit-2026-07-01";

  List<BetaMessageParam> requestMessages =
  [
      new() { Role = Role.User, Content = "Hello, Claude" },
  ];
  MessageCreateParams Request(Model model) => new()
  {
      Model = model,
      MaxTokens = 1024,
      Messages = requestMessages,
      Betas = [beta],
  };
  var response = await client.Beta.Messages.Create(Request(Model.ClaudeFable5));

  if (
      response.StopReason == BetaStopReason.Refusal
      && response.StopDetails is { FallbackCreditToken: string token } details
  )
  {
      var exactBody = Request(Model.ClaudeOpus4_8) with { FallbackCreditToken = token };
      var attempt = exactBody;
      // Privilégier la forme de continuation sauf si l'assertion est fausse
      if (details.FallbackHasPrefillClaim is not false)
      {
          var echoed = JsonArray.Create(response.RawData["content"])!;
          if (
              echoed is [.., JsonObject lastBlock]
              && lastBlock["type"]?.GetValue<string>() is "text"
              && lastBlock["text"]?.GetValue<string>() is string text
          )
          {
              lastBlock["text"] = text.TrimEnd();
          }
          attempt = exactBody with
          {
              Messages =
              [
                  .. requestMessages,
                  new()
                  {
                      Role = Role.Assistant,
                      Content = new BetaMessageParamContent(
                          JsonSerializer.SerializeToElement(echoed)
                      ),
                  },
              ],
          };
      }
      // Un rejet transitoire « redemption temporarily unavailable » se propage hors de
      // chacun des filtres catch suivants : réessayer avec le jeton dans sa fenêtre de cinq minutes.
      try
      {
          response = await client.Beta.Messages.Create(attempt);
      }
      catch (AnthropicBadRequestException e)
          when (!e.Message.Contains("redemption temporarily unavailable"))
      {
          try
          {
              // Revenir au corps inchangé, toujours avec le jeton
              response = await client.Beta.Messages.Create(exactBody);
          }
          catch (AnthropicBadRequestException retryError)
              when (!retryError.Message.Contains("redemption temporarily unavailable"))
          {
              // Le jeton lui-même a été rejeté : y renoncer et réessayer sans lui.
              response = await client.Beta.Messages.Create(Request(Model.ClaudeOpus4_8));
          }
      }
  }

  Console.WriteLine(
      JsonSerializer.Serialize(
          new { stop_reason = response.StopReason?.Raw(), model = response.Model.Raw() }
      )
  );
  ```

  ```go Go
  ctx := context.Background()
  client := anthropic.NewClient()

  request := anthropic.BetaMessageNewParams{
  	MaxTokens: 1024,
  	Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaFallbackCredit2026_07_01},
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Hello, Claude")),
  	},
  }

  send := func(model anthropic.Model, body anthropic.BetaMessageNewParams) (*anthropic.BetaMessage, error) {
  	body.Model = model
  	return client.Beta.Messages.New(ctx, body)
  }
  // Un 400 non transitoire signifie que cette forme de tentative ou ce jeton a été rejeté et
  // que l'échelon suivant de l'échelle doit s'exécuter. « redemption temporarily
  // unavailable » est transitoire : signalez-le et réessayez avec le jeton dans
  // sa fenêtre de cinq minutes.
  canFallBack := func(err error) bool {
  	apiErr, ok := errors.AsType[*anthropic.Error](err)
  	return ok && apiErr.StatusCode == 400 &&
  		!strings.Contains(apiErr.Error(), "redemption temporarily unavailable")
  }

  response, err := send(anthropic.ModelClaudeFable5, request)
  if err != nil {
  	log.Fatal(err)
  }

  if response.StopReason == anthropic.BetaStopReasonRefusal {
  	details := response.StopDetails
  	if token := details.FallbackCreditToken; token != "" {
  		exactBody := request
  		exactBody.FallbackCreditToken = anthropic.BetaMessageNewParamsFallbackCreditTokenUnion{
  			OfString: anthropic.String(token),
  		}
  		attempt := exactBody
  		// Préférez la forme de continuation sauf si l'affirmation est fausse.
  		if details.FallbackHasPrefillClaim || !details.JSON.FallbackHasPrefillClaim.Valid() {
  			echoed := response.ToParam()
  			if len(echoed.Content) > 0 {
  				if text := echoed.Content[len(echoed.Content)-1].OfText; text != nil {
  					text.Text = strings.TrimRightFunc(text.Text, unicode.IsSpace)
  				}
  			}
  			attempt.Messages = append(slices.Clone(request.Messages), echoed)
  		}
  		response, err = send(anthropic.ModelClaudeOpus4_8, attempt)
  		if err != nil && canFallBack(err) {
  			// Repli sur le corps inchangé, toujours avec le jeton.
  			response, err = send(anthropic.ModelClaudeOpus4_8, exactBody)
  			if err != nil && canFallBack(err) {
  				// Le jeton lui-même a été rejeté : abandonnez-le et réessayez sans.
  				response, err = send(anthropic.ModelClaudeOpus4_8, request)
  			}
  		}
  		if err != nil {
  			log.Fatal(err)
  		}
  	}
  }

  summary, err := json.Marshal(struct {
  	StopReason anthropic.BetaStopReason `json:"stop_reason"`
  	Model      anthropic.Model          `json:"model"`
  }{response.StopReason, response.Model})
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(string(summary))
  ```

  ```java Java
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  MessageCreateParams.Builder request() {
      return MessageCreateParams.builder()
          .maxTokens(1024L)
          .addUserMessage("Hello, Claude")
          .addBeta(AnthropicBeta.FALLBACK_CREDIT_2026_07_01);
  }

  BetaMessage send(Model model, MessageCreateParams.Builder body) {
      return client.beta().messages().create(body.model(model).build());
  }

  void main() {
      BetaMessage response = send(Model.CLAUDE_FABLE_5, request());

      if (response.stopReason().map(BetaStopReason.REFUSAL::equals).orElse(false)
              && response.stopDetails().orElse(null) instanceof BetaRefusalStopDetails details
              && details.fallbackCreditToken().orElse(null) instanceof String creditToken) {
          MessageCreateParams.Builder attempt = request().fallbackCreditToken(creditToken);
          // Privilégier la forme de continuation sauf si l'assertion est fausse
          if (details.fallbackHasPrefillClaim().orElse(true)) {
              List<BetaContentBlockParam> echoed = new ArrayList<>(
                  response.content().stream().map(BetaContentBlock::toParam).toList());
              if (!echoed.isEmpty() && echoed.getLast().isText()) {
                  var lastText = echoed.removeLast().asText();
                  echoed.addLast(BetaContentBlockParam.ofText(
                      lastText.toBuilder().text(lastText.text().stripTrailing()).build()));
              }
              attempt.addAssistantMessageOfBetaContentBlockParams(echoed);
          }
          try {
              response = send(Model.CLAUDE_OPUS_4_8, attempt);
          } catch (BadRequestException badRequest) {
              // Transitoire : réessayer avec le jeton dans sa fenêtre de cinq minutes
              if (badRequest.getMessage().contains("redemption temporarily unavailable")) {
                  throw badRequest;
              }
              try {
                  // Repli sur le corps inchangé, toujours avec le jeton
                  response = send(Model.CLAUDE_OPUS_4_8, request().fallbackCreditToken(creditToken));
              } catch (BadRequestException retryBadRequest) {
                  if (retryBadRequest.getMessage().contains("redemption temporarily unavailable")) {
                      throw retryBadRequest;
                  }
                  // Le jeton lui-même a été rejeté : y renoncer et réessayer sans lui.
                  response = send(Model.CLAUDE_OPUS_4_8, request());
              }
          }
      }

      IO.println("""
          {"stop_reason": "%s", "model": "%s"}"""
          .formatted(response.stopReason().orElseThrow(), response.model()));
  }
  ```

  ```php PHP
  $client = new Client();
  $beta = 'fallback-credit-2026-07-01';
  $messages = [['role' => 'user', 'content' => 'Hello, Claude']];

  $send = fn (string $model, array $messages, ?string $token = null) => $client->beta->messages->create(
      maxTokens: 1024,
      messages: $messages,
      model: $model,
      fallbackCreditToken: $token,
      betas: [$beta],
  );
  $response = $send('claude-fable-5', $messages);

  $token = $response->stopReason === 'refusal'
      ? $response->stopDetails?->fallbackCreditToken
      : null;

  if ($token !== null) {
      $attemptMessages = $messages;
      // Privilégier la forme de continuation sauf si l'affirmation est fausse
      if ($response->stopDetails->fallbackHasPrefillClaim !== false) {
          $echoed = $response->content
              |> json_encode(...)
              |> (fn (string $json): array => json_decode($json, associative: true));
          $lastIndex = array_key_last($echoed);
          if ($lastIndex !== null && $echoed[$lastIndex]['type'] === 'text') {
              $echoed[$lastIndex]['text'] = rtrim($echoed[$lastIndex]['text']);
          }
          $attemptMessages[] = ['role' => 'assistant', 'content' => $echoed];
      }
      // Transitoire : réessayer avec le jeton dans sa fenêtre de cinq minutes
      $isTransientRedemption = fn (BadRequestException $error): bool =>
          str_contains($error->getMessage(), 'redemption temporarily unavailable');
      try {
          $response = $send('claude-opus-4-8', $attemptMessages, $token);
      } catch (BadRequestException $error) {
          if ($isTransientRedemption($error)) {
              throw $error;
          }
          try {
              // Repli sur le corps inchangé, toujours avec le jeton
              $response = $send('claude-opus-4-8', $messages, $token);
          } catch (BadRequestException $retryError) {
              if ($isTransientRedemption($retryError)) {
                  throw $retryError;
              }
              // Le jeton lui-même a été rejeté : y renoncer et réessayer sans lui.
              $response = $send('claude-opus-4-8', $messages);
          }
      }
  }

  echo json_encode(['stop_reason' => $response->stopReason, 'model' => $response->model]), PHP_EOL;
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  request = {
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello, Claude"}]
  }

  send_message = ->(model, body) do
    client.beta.messages.create(model:, betas: ["fallback-credit-2026-07-01"], **body)
  end

  response = send_message.call("claude-fable-5", request)

  if response in {stop_reason: :refusal,
                  stop_details: {fallback_credit_token: String => credit_token} => details}
    exact_body = request.merge(fallback_credit_token: credit_token)

    # Privilégier la forme de continuation sauf si l'affirmation est fausse
    attempt = if details.fallback_has_prefill_claim != false
      echoed = response.content.map(&:to_h)
      if echoed.last in {type: :text, text: String => final_text}
        echoed[-1] = echoed.last.merge(text: final_text.rstrip)
      end
      exact_body.merge(
        messages: [*request[:messages], {role: "assistant", content: echoed}]
      )
    else
      exact_body
    end

    begin
      response = send_message.call("claude-opus-4-8", attempt)
    rescue Anthropic::Errors::BadRequestError => error
      # Transitoire : réessayer avec le jeton dans sa fenêtre de cinq minutes
      raise if error.message.include?("redemption temporarily unavailable")
      begin
        # Repli sur le corps inchangé, toujours avec le jeton
        response = send_message.call("claude-opus-4-8", exact_body)
      rescue Anthropic::Errors::BadRequestError => error
        # Transitoire : réessayer avec le jeton dans sa fenêtre de cinq minutes
        raise if error.message.include?("redemption temporarily unavailable")
        # Le jeton lui-même a été rejeté : l'abandonner et réessayer sans lui.
        response = send_message.call("claude-opus-4-8", request)
      end
    end
  end

  puts JSON.generate({stop_reason: response.stop_reason, model: response.model})
  ```
</CodeGroup>

## Où cela fonctionne

Le crédit de repli est en bêta sur la Claude API, Amazon Bedrock, Claude Platform on AWS, Google Cloud et Microsoft Foundry. Les refus dans les [Message Batches](https://platform.claude.com/docs/fr/build-with-claude/batch-processing) ne génèrent pas de jetons de crédit, et l'utilisation des jetons ne s'applique qu'aux requêtes directes à l'API Messages : un jeton transmis dans une requête par lot est accepté mais ignoré. Un refus de Claude Haiku 5.5 ne comporte aucun crédit de repli ; une nouvelle tentative après un tel refus paie donc le coût complet de l'écriture du cache de prompts du modèle de repli.

Le modèle de la nouvelle tentative doit faire partie des cibles de repli autorisées du modèle ayant refusé. Pour Claude Fable 5.1, Claude Fable 5 et Claude Opus 5.5, il s'agit de Claude Opus 4.8 (`claude-opus-4-8`) et Claude Opus 5 (`claude-opus-5`). Pour Claude Opus 5, il s'agit de Claude Opus 4.8. Pour Claude Sonnet 5.5, il s'agit de Claude Sonnet 5 (`claude-sonnet-5`).

<Accordion title="Rechercher les cibles de repli autorisées par programmation">
  Sur la Claude API et Claude Platform sur AWS, la liste des cibles est publiée sous `allowed_fallback_models` dans l'entrée de chaque modèle de l'[API Models](https://platform.claude.com/docs/fr/api/models/list) lorsque l'en-tête bêta `server-side-fallback-2026-07-01` est défini. La liste n'est pas encore visible avec l'en-tête `fallback-credit-*` seul. Elle n'est pas exposée sur Amazon Bedrock, Google Cloud ni Microsoft Foundry.
</Accordion>

## Vérifier que le crédit a été appliqué

Le remboursement est visible dans le champ `usage` de la nouvelle tentative. Par rapport à ce que la même requête indiquerait sans le jeton, `cache_creation_input_tokens` est plus bas et `cache_read_input_tokens` est plus élevé du même montant. Un décalage nul signifie que le jeton a été honoré mais qu'il n'y avait rien à refacturer, par exemple parce que le cache du modèle de la nouvelle tentative était déjà chaud.

## Lorsqu'une nouvelle tentative est rejetée

La plupart des nouvelles tentatives utilisent le crédit dès le premier essai. Lorsque ce n'est pas le cas, l'API renvoie une erreur 400 qui vous indique quoi essayer ensuite.

<Steps>
  <Step title="Continuation rejetée : renvoyez le corps inchangé">
    Si la nouvelle tentative qui ajoute le message assistant est rejetée avec une erreur 400, renvoyez le corps de la requête refusée inchangé, toujours avec le jeton.
  </Step>

  <Step title="Jeton rejeté : supprimez le jeton">
    Si le corps inchangé est également rejeté avec une erreur 400 dont le message mentionne `fallback_credit_token`, relancez sans le jeton. Le crédit est perdu, mais la nouvelle tentative elle-même aboutit.
  </Step>
</Steps>

<Note>
  Si la requête refusée a exécuté des outils serveur, une nouvelle tentative sans jeton réexécute et refacture ces outils. Dans ce cas, remontez l'erreur 400 à votre appelant au lieu de basculer vers une nouvelle tentative sans jeton.
</Note>

<Accordion title="Si l'erreur indique « redemption temporarily unavailable »">
  Ce rejet est transitoire, et non un verdict sur la forme de votre nouvelle tentative. Relancez la même requête, avec le même jeton, dans la fenêtre de cinq minutes du jeton. Ne passez pas à l'étape suivante de l'échelle.
</Accordion>

## Référence

Les sections suivantes couvrent les cas limites et les règles complètes d'utilisation du crédit. La plupart des intégrations n'en ont pas besoin.

<Accordion title="Champs qui doivent correspondre à la requête refusée">
  L'utilisation du crédit compare la nouvelle tentative à la requête refusée. Chaque champ qui façonne le prompt doit correspondre exactement. Les champs qui ne façonnent pas le prompt peuvent changer lors de la nouvelle tentative.

  | Règle                                         | Champs                                                                                                                                                                          |
  | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | Doivent correspondre exactement               | `system`, `messages`, `tools`, `tool_choice`, `thinking` et `cache_control`, plus `output_config`, `mcp_servers`, `context_management` et `container` lorsque vous les utilisez |
  | Peuvent changer lors de la nouvelle tentative | `model`, `max_tokens`, `stop_sequences`, `temperature`, `top_p`, `top_k`, `stream`, `metadata` et `service_tier`                                                                |

  La forme de continuation (`fallback_has_prefill_claim: true`) est la seule exception à la correspondance de `messages` : elle ajoute exactement un message assistant à la fin de `messages`.

  Ne retirez pas les blocs `thinking` ou `redacted_thinking` des tours précédents lors de la nouvelle tentative, même si une relance simple sans jeton les retire habituellement. Le corps doit correspondre à la requête refusée, et le serveur gère lui-même ces blocs.
</Accordion>

<Accordion title="Les en-têtes bêta doivent également correspondre">
  Envoyez les mêmes en-têtes `anthropic-beta` sur la nouvelle tentative que sur la requête refusée. Un en-tête bêta présent sur l'une des deux requêtes mais pas sur l'autre peut faire échouer la correspondance même lorsque les corps sont identiques. L'erreur 400 qui en résulte porte le même message `request body ... does not match` qu'une différence de corps, de sorte qu'une différence d'en-tête est facile à confondre avec un problème de corps. En particulier, n'ajoutez ni ne supprimez d'en-têtes bêta en fonction du modèle ciblé par la requête.

  Deux familles d'en-têtes sont exemptées de la correspondance, dans l'intérêt de la nouvelle tentative :

  * **`server-side-fallback-*` :** une nouvelle tentative doit supprimer le paramètre `fallbacks`, et supprimer cet en-tête en même temps ne provoque pas de non-correspondance.
  * **`fallback-credit-*` :** conservez cet en-tête sur les deux requêtes. La nouvelle tentative en a besoin pour utiliser le jeton.

  <Note>
    Sur les modèles qui incluent par défaut la fenêtre de contexte de 1M tokens, tels que Claude Fable 5.1, Claude Fable 5, Claude Opus 5.5, Claude Opus 5, Claude Opus 4.8, Claude Sonnet 5.5 et Claude Sonnet 5, l'en-tête bêta `context-1m-2025-08-07` n'a aucun effet. Pour que les deux requêtes restent identiques, omettez cet en-tête sur les deux plutôt que de l'envoyer sur l'une et pas sur l'autre.
  </Note>
</Accordion>

<Accordion title="Lorsque fallback_has_prefill_claim est absent">
  Le champ n'a pas de valeur uniquement lorsque le jeton n'en a pas non plus ; ainsi, tant que vous détenez un jeton, le champ a une valeur, sauf sur Amazon Bedrock, Google Cloud et Microsoft Foundry, où il peut encore être absent pendant le déploiement de leur prise en charge de ce champ. Dans ce cas, considérez la forme de la nouvelle tentative comme inconnue plutôt que comme `false` (python: `False`). Essayez d'abord la forme avec le message assistant ajouté, et appuyez-vous sur la gestion des rejets décrite dans [Lorsqu'une nouvelle tentative est rejetée](https://platform.claude.com/docs/fr/build-with-claude/fallback-credit#when-a-retry-is-rejected), qui se replie sur le corps inchangé.
</Accordion>

<Accordion title="Reprendre le contenu de la réponse refusée">
  Lorsque le jeton d'un refus prend en charge la forme de continuation, le `content` de la réponse ne contient que la sortie propre du modèle, et l'explication du refus est fournie dans `stop_details.explanation`. Vous pouvez donc reprendre `content` tel quel dans le message assistant ajouté.

  Deux ajustements peuvent encore être nécessaires avant l'envoi :

  * Si le dernier bloc que vous envoyez est un bloc `text`, supprimez ses espaces de fin.
  * Omettez tout bloc `tool_use` côté client qui n'a pas de `tool_result` correspondant.

  Si le contenu repris inclut un bloc `fallback` issu d'un [repli côté serveur](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback#server-side-fallback) antérieur, conservez le bloc exactement là où il apparaissait. Il est accepté sur toute requête sans en-tête bêta. L'API utilise sa position pour valider les blocs de réflexion qui l'entourent, de sorte qu'une requête qui reprend des blocs de réflexion des deux côtés de cette frontière est rejetée si le bloc est omis ou déplacé.
</Accordion>

<Accordion title="Portée et durée de vie du jeton">
  Le jeton ne peut être utilisé que depuis l'organisation et l'espace de travail qui ont reçu le refus, y compris sur Microsoft Foundry. Sur Amazon Bedrock et Google Cloud, qui n'ont pas d'espaces de travail, le jeton est lié à l'identité de l'appelant de la plateforme à la place.

  Le jeton expire cinq minutes après le refus. Passé ce délai, envoyez la nouvelle tentative sans lui. Le jeton est également sans état : le serveur ne stocke rien à son sujet, et il n'existe aucun point de terminaison pour l'inspecter ou le révoquer.
</Accordion>

<Accordion title="Lorsqu'un jeton ne peut être utilisé par aucune des deux formes">
  Lorsque le refus est survenu après que des outils serveur ont déjà été exécutés au sein de la requête, le jeton ne peut être utilisé qu'en poursuivant la réponse partielle. C'est cette restriction qui empêche les appels d'outils terminés d'être exécutés, et facturés, à nouveau.

  Une combinaison peut donc rendre le jeton inutilisable par l'une ou l'autre forme, lorsque les deux conditions suivantes sont réunies :

  * La requête utilisait `output_config.format` ou un `tool_choice` qui force l'utilisation d'outils. L'un comme l'autre exclut la forme avec message assistant ajouté.
  * Le refus est survenu après l'exécution d'outils serveur. Cela exclut le corps inchangé.

  Si la nouvelle tentative avec corps inchangé est rejetée avec une erreur 400 indiquant que le jeton doit être utilisé en poursuivant la réponse partielle, abandonnez le jeton. Une nouvelle tentative sans lui aboutit, mais elle réexécute et refacture les outils serveur terminés. Remontez le coût ou l'erreur à votre appelant plutôt que de relancer silencieusement.
</Accordion>

## Étapes suivantes

<CardGroup>
  <Card title="Refus et repli" icon="shield" href="https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback">
    Détectez les refus et choisissez entre le repli côté serveur, le middleware du SDK et une nouvelle tentative manuelle.
  </Card>

  <Card title="Mise en cache des prompts" icon="bolt" href="https://platform.claude.com/docs/fr/build-with-claude/prompt-caching">
    Comment les lectures en cache et les écritures en cache sont facturées.
  </Card>

  <Card title="Raisons d'arrêt et repli" icon="code" href="https://platform.claude.com/docs/fr/build-with-claude/handling-stop-reasons">
    Chaque valeur de `stop_reason` et comment la gérer.
  </Card>

  <Card title="Middleware du SDK" icon="settings" href="https://platform.claude.com/docs/fr/cli-sdks-libraries/middleware">
    L'utilitaire du SDK qui applique automatiquement le crédit de repli.
  </Card>
</CardGroup>
