---
title: Crédito de fallback
url: https://platform.claude.com/docs/pt-BR/build-with-claude/fallback-credit
description: Evite pagar o custo do cache de prompt duas vezes ao repetir uma solicitação recusada em outro modelo.
---

Os caches de prompt são por modelo. Quando um modelo recusa uma solicitação e você a repete em outro modelo, o prefixo da conversa já armazenado em cache para o primeiro modelo precisa ser gravado no cache do novo modelo do zero. Gravações em cache custam mais do que leituras de cache. O "fallback credit" (crédito de fallback) elimina esse custo extra. A recusa carrega um token de crédito, você ecoa o token na nova tentativa, e a nova tentativa é cobrada como se a conversa tivesse ocorrido no novo modelo desde o início.

Você só precisa desta página quando constrói a nova tentativa por conta própria: via HTTP bruto ou com lógica de repetição personalizada. O [fallback do lado do servidor](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback#server-side-fallback) e o [middleware do SDK](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback#client-side-fallback) aplicam o crédito de fallback automaticamente. Se você usa qualquer um deles, pule esta página.

[Recusas e fallback](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback) aborda a detecção de recusas e a escolha de uma abordagem de fallback. [Cache de prompt](https://platform.claude.com/docs/pt-BR/build-with-claude/prompt-caching) explica leituras de cache e gravações em cache, caso esses termos sejam novos para você.

## O fluxo básico

<Steps>
  <Step title="Ative com o cabeçalho beta">
    Envie a solicitação que pode ser recusada com o cabeçalho `anthropic-beta: fallback-credit-2026-07-01`. O cabeçalho `server-side-fallback-2026-07-01` também concede os mesmos campos, exceto no Amazon Bedrock e no Google Cloud, que retornam um erro 400 para esse cabeçalho. O cabeçalho anterior `fallback-credit-2026-06-01` continua sendo aceito e concede os mesmos campos.
  </Step>

  <Step title="Leia dois campos da recusa">
    Em uma recusa, `stop_details` inclui dois campos:

    * **`fallback_credit_token`:** uma string opaca que representa o crédito.
    * **`fallback_has_prefill_claim`:** um booleano que informa qual formato de corpo de nova tentativa usar.

    Ambos são `null` quando não há crédito disponível para a recusa.
  </Step>

  <Step title="Construa a nova tentativa">
    Comece a partir do corpo da solicitação recusada. Defina `model` como o modelo de fallback e adicione o token como o parâmetro de nível superior `fallback_credit_token`. Escolha o formato do corpo na tabela a seguir.
  </Step>

  <Step title="Envie a nova tentativa com o mesmo cabeçalho">
    Envie a nova tentativa com o mesmo cabeçalho beta `fallback-credit-2026-07-01`. A nova tentativa precisa do cabeçalho para resgatar o token.
  </Step>
</Steps>

O campo `fallback_has_prefill_claim` informa se a nova tentativa pode continuar a saída parcial do modelo que recusou em vez de recomeçar:

| `fallback_has_prefill_claim` | Corpo da nova tentativa                                                                                                                                                                                                                                                                                 |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `true`                       | O corpo da solicitação recusada, inalterado, mais uma mensagem de assistente anexada cujo `content` ecoa o `content` da resposta recusada. O modelo da nova tentativa continua a resposta de onde o modelo que recusou parou, e as chamadas de ferramentas de servidor concluídas não são reexecutadas. |
| `false`                      | O corpo da solicitação recusada, inalterado.                                                                                                                                                                                                                                                            |

## Exemplo

O exemplo a seguir faz uma solicitação que pode ser recusada e resgata o token de crédito em uma nova tentativa no Claude Opus 4.8. Quando uma tentativa de repetição é rejeitada, o exemplo degrada pela escada de rejeição: a sequência de formatos de nova tentativa progressivamente mais simples abordada em [Quando uma nova tentativa é rejeitada](https://platform.claude.com/docs/pt-BR/build-with-claude/fallback-credit#when-a-retry-is-rejected).

<CodeGroup>
  ```bash cURL
  # Requisição inicial (pode ser recusada)
  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"}]
    }')

  # Uma recusa traz um token de crédito de uso único em stop_details
  token=$(jq -r '.stop_details.fallback_credit_token // empty' <<<"${response}")

  if [[ -n "${token}" ]]; then
    # Tente novamente no modelo de fallback com o token de crédito (mesmo corpo)
    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

  # Veja os exemplos do SDK para a sequência completa de tratamento de rejeições.
  jq -c '{stop_reason, model}' <<<"${response}"
  ```

  ```bash CLI
  # Requisição inicial (pode ser recusada)
  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)

  # Uma recusa traz um token de crédito de uso único em stop_details
  token=$(jq -r '.stop_details.fallback_credit_token // empty' <<<"${response}")

  if [[ -n "${token}" ]]; then
    # Tente novamente no modelo de fallback com o token de crédito
    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

  # Veja os exemplos do SDK para a sequência completa de tratamento de rejeições.
  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}
      # Prefira o formato de continuação, a menos que a afirmação seja 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:
              # Recorra ao corpo inalterado, ainda com o token
              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
              # O próprio token foi rejeitado: descarte-o e tente novamente sem ele.
              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
    };

    // Forma mais rica primeiro, degradando a cada rejeição: a forma de
    // continuação (a menos que a alegação seja falsa), o corpo inalterado ainda
    // carregando o token e, por fim, abrindo mão do token.
    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) {
      // Degrade apenas em um 400 relacionado à forma. "redemption temporarily
      // unavailable" é transitório: tente novamente da mesma forma dentro da
      // janela de cinco minutos do token.
      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;
      // Prefira o formato de continuação, a menos que a afirmação seja falsa
      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)
                      ),
                  },
              ],
          };
      }
      // Uma rejeição transitória "redemption temporarily unavailable" se propaga para fora de
      // cada um dos filtros catch a seguir: tente novamente com o token dentro da janela de cinco minutos.
      try
      {
          response = await client.Beta.Messages.Create(attempt);
      }
      catch (AnthropicBadRequestException e)
          when (!e.Message.Contains("redemption temporarily unavailable"))
      {
          try
          {
              // Recorra ao corpo inalterado, ainda com o token
              response = await client.Beta.Messages.Create(exactBody);
          }
          catch (AnthropicBadRequestException retryError)
              when (!retryError.Message.Contains("redemption temporarily unavailable"))
          {
              // O próprio token foi rejeitado: descarte-o e tente novamente sem ele.
              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)
  }
  // Um 400 não transitório significa que este formato de tentativa ou token foi rejeitado e
  // o próximo degrau da escada deve ser executado. "redemption temporarily
  // unavailable" é transitório: exiba-o e tente novamente com o token dentro
  // de sua janela de cinco minutos.
  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
  		// Prefira o formato de continuação, a menos que a afirmação seja falsa
  		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) {
  			// Recorra ao corpo inalterado, ainda com o token
  			response, err = send(anthropic.ModelClaudeOpus4_8, exactBody)
  			if err != nil && canFallBack(err) {
  				// O próprio token foi rejeitado: descarte-o e tente novamente sem ele.
  				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);
          // Prefira o formato de continuação, a menos que a afirmação seja falsa
          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) {
              // Transitório: tente novamente com o token dentro da janela de cinco minutos
              if (badRequest.getMessage().contains("redemption temporarily unavailable")) {
                  throw badRequest;
              }
              try {
                  // Recorra ao corpo inalterado, ainda com o token
                  response = send(Model.CLAUDE_OPUS_4_8, request().fallbackCreditToken(creditToken));
              } catch (BadRequestException retryBadRequest) {
                  if (retryBadRequest.getMessage().contains("redemption temporarily unavailable")) {
                      throw retryBadRequest;
                  }
                  // O próprio token foi rejeitado: descarte-o e tente novamente sem ele.
                  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;
      // Prefira o formato de continuação, a menos que a afirmação seja falsa
      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];
      }
      // Transitório: tente novamente com o token dentro da janela de cinco minutos
      $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 {
              // Recorra ao corpo inalterado, ainda com o token
              $response = $send('claude-opus-4-8', $messages, $token);
          } catch (BadRequestException $retryError) {
              if ($isTransientRedemption($retryError)) {
                  throw $retryError;
              }
              // O próprio token foi rejeitado: descarte-o e tente novamente sem ele.
              $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)

    # Prefira o formato de continuação, a menos que a afirmação seja falsa
    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
      # Transitório: tente novamente com o token dentro da janela de cinco minutos
      raise if error.message.include?("redemption temporarily unavailable")
      begin
        # Recorra ao corpo inalterado, ainda com o token
        response = send_message.call("claude-opus-4-8", exact_body)
      rescue Anthropic::Errors::BadRequestError => error
        # Transitório: tente novamente com o token dentro da janela de cinco minutos
        raise if error.message.include?("redemption temporarily unavailable")
        # O próprio token foi rejeitado: descarte-o e tente novamente sem ele.
        response = send_message.call("claude-opus-4-8", request)
      end
    end
  end

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

## Onde funciona

O crédito de fallback está em beta na Claude API, no Amazon Bedrock, na Claude Platform on AWS, no Google Cloud e no Microsoft Foundry. Recusas em [Message Batches](https://platform.claude.com/docs/pt-BR/build-with-claude/batch-processing) não geram tokens de crédito, e o resgate se aplica apenas a solicitações diretas à Messages API: um token passado em uma solicitação em lote é aceito, mas ignorado. Uma recusa do Claude Haiku 5.5 não carrega crédito de fallback, portanto uma nova tentativa após ela paga o custo total de gravar o cache de prompt do modelo de fallback.

O modelo da nova tentativa deve ser um dos destinos de fallback permitidos do modelo que recusou. Para Claude Fable 5.1, Claude Fable 5 e Claude Opus 5.5, esses destinos são Claude Opus 4.8 (`claude-opus-4-8`) e Claude Opus 5 (`claude-opus-5`). Para Claude Opus 5, é o Claude Opus 4.8. Para Claude Sonnet 5.5, é o Claude Sonnet 5 (`claude-sonnet-5`).

<Accordion title="Consultando destinos de fallback permitidos programaticamente">
  Na Claude API e na Claude Platform on AWS, a lista de destinos é publicada como `allowed_fallback_models` na entrada de cada modelo na [Models API](https://platform.claude.com/docs/pt-BR/api/models/list) quando o cabeçalho beta `server-side-fallback-2026-07-01` está definido. A lista ainda não é visível apenas com o cabeçalho `fallback-credit-*`. Ela não é exposta no Amazon Bedrock, Google Cloud ou Microsoft Foundry.
</Accordion>

## Verificando se o crédito foi aplicado

O reembolso é visível no `usage` da nova tentativa. Em comparação com o que a mesma solicitação reportaria sem o token, `cache_creation_input_tokens` é menor e `cache_read_input_tokens` é maior na mesma quantidade. Uma variação de zero significa que o token foi honrado, mas não havia nada a reprecificar, por exemplo porque o cache do modelo da nova tentativa já estava aquecido.

## Quando uma nova tentativa é rejeitada

A maioria das novas tentativas é resgatada na primeira tentativa. Quando uma não é, a API retorna um erro 400 que informa o que tentar em seguida.

<Steps>
  <Step title="Continuação rejeitada: reenvie o corpo inalterado">
    Se a nova tentativa que anexa a mensagem de assistente for rejeitada com um erro 400, reenvie o corpo da solicitação recusada inalterado, ainda com o token.
  </Step>

  <Step title="Token rejeitado: remova o token">
    Se o corpo inalterado também for rejeitado com um erro 400 cuja mensagem menciona `fallback_credit_token`, tente novamente sem o token. O crédito é perdido, mas a nova tentativa em si é processada.
  </Step>
</Steps>

<Note>
  Se a solicitação recusada executou ferramentas de servidor, uma nova tentativa sem token reexecuta e cobra novamente essas ferramentas. Nesse caso, exponha o erro 400 ao seu chamador em vez de prosseguir para uma nova tentativa sem token.
</Note>

<Accordion title="Se o erro disser 'redemption temporarily unavailable'">
  Essa rejeição é transitória, não um veredito sobre o formato da sua nova tentativa. Repita a mesma solicitação, com o mesmo token, dentro da janela de cinco minutos do token. Não avance para o próximo degrau da escada.
</Accordion>

## Referência

As seções a seguir abordam casos extremos e as regras completas de resgate. A maioria das integrações não precisa delas.

<Accordion title="Campos que devem corresponder à solicitação recusada">
  O resgate compara a nova tentativa com a solicitação recusada. Todo campo que molda o prompt deve corresponder exatamente. Campos que não moldam o prompt podem mudar na nova tentativa.

  | Regra                         | Campos                                                                                                                                                                    |
  | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | Devem corresponder exatamente | `system`, `messages`, `tools`, `tool_choice`, `thinking` e `cache_control`, além de `output_config`, `mcp_servers`, `context_management` e `container` quando você os usa |
  | Podem mudar na nova tentativa | `model`, `max_tokens`, `stop_sequences`, `temperature`, `top_p`, `top_k`, `stream`, `metadata` e `service_tier`                                                           |

  O formato de continuação (`fallback_has_prefill_claim: true`) é a única exceção à correspondência de `messages`: ele adiciona exatamente uma mensagem de assistente ao final de `messages`.

  Não remova blocos `thinking` ou `redacted_thinking` de turnos anteriores na nova tentativa, mesmo que uma nova tentativa simples sem token normalmente os remova. O corpo deve corresponder à solicitação recusada, e o servidor lida com esses blocos por conta própria.
</Accordion>

<Accordion title="Os cabeçalhos beta também devem corresponder">
  Envie os mesmos cabeçalhos `anthropic-beta` na nova tentativa e na solicitação recusada. Um cabeçalho beta presente em uma das duas solicitações, mas não na outra, pode fazer a correspondência falhar mesmo quando os corpos são idênticos. O erro 400 resultante carrega a mesma mensagem `request body ... does not match` de uma diferença de corpo, então uma diferença de cabeçalho é fácil de ser interpretada erroneamente como um problema de corpo. Em particular, não adicione nem remova cabeçalhos beta com base no modelo ao qual a solicitação se destina.

  Duas famílias de cabeçalhos estão isentas da correspondência, em benefício da nova tentativa:

  * **`server-side-fallback-*`:** uma nova tentativa deve remover o parâmetro `fallbacks`, e remover esse cabeçalho junto com ele não causa uma incompatibilidade.
  * **`fallback-credit-*`:** mantenha esse cabeçalho em ambas as solicitações. A nova tentativa precisa dele para resgatar o token.

  <Note>
    Em modelos que incluem a janela de contexto de 1M de tokens por padrão, como Claude Fable 5.1, Claude Fable 5, Claude Opus 5.5, Claude Opus 5, Claude Opus 4.8, Claude Sonnet 5.5 e Claude Sonnet 5, o cabeçalho beta `context-1m-2025-08-07` não tem efeito. Para manter as duas solicitações idênticas, omita esse cabeçalho em ambas em vez de enviá-lo em uma e não na outra.
  </Note>
</Accordion>

<Accordion title="Quando fallback_has_prefill_claim está ausente">
  O campo só fica sem valor quando o token também não tem valor, então, enquanto você tiver um token, o campo terá um valor, exceto no Amazon Bedrock, no Google Cloud e no Microsoft Foundry, onde ele ainda pode estar ausente enquanto o suporte ao campo é implantado. Nesse caso, trate o formato da nova tentativa como desconhecido, e não como `false` (python: `False`). Tente primeiro o formato com a mensagem de assistente anexada e conte com o tratamento de rejeição descrito em [Quando uma nova tentativa é rejeitada](https://platform.claude.com/docs/pt-BR/build-with-claude/fallback-credit#when-a-retry-is-rejected), que recorre ao corpo inalterado.
</Accordion>

<Accordion title="Ecoando o content da resposta recusada">
  Quando o token de uma recusa suporta o formato de continuação, o `content` da resposta carrega apenas a saída do próprio modelo, e a explicação da recusa é entregue em `stop_details.explanation`. Portanto, você pode ecoar `content` na mensagem de assistente anexada como está.

  Dois ajustes ainda podem ser necessários antes do envio:

  * Se o bloco final que você envia for um bloco `text`, remova seus espaços em branco finais.
  * Omita qualquer bloco `tool_use` do lado do cliente que não tenha um `tool_result` correspondente.

  Se o conteúdo ecoado incluir um bloco `fallback` de um [fallback do lado do servidor](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback#server-side-fallback) anterior, mantenha o bloco exatamente onde ele apareceu. Ele é aceito em qualquer solicitação sem um cabeçalho beta. A API usa sua posição para validar os blocos de pensamento ao redor dele, então uma solicitação que ecoa blocos de pensamento de ambos os lados dessa fronteira é rejeitada se o bloco for omitido ou movido.
</Accordion>

<Accordion title="Escopo e tempo de vida do token">
  O token só pode ser resgatado pela organização e pelo workspace que receberam a recusa, inclusive no Microsoft Foundry. No Amazon Bedrock e no Google Cloud, que não têm workspaces, o token é vinculado à identidade do chamador da plataforma.

  O token expira cinco minutos após a recusa. Depois disso, envie a nova tentativa sem ele. O token também é stateless: o servidor não armazena nada sobre ele, e não há endpoint para inspecioná-lo ou revogá-lo.
</Accordion>

<Accordion title="Quando um token não pode ser resgatado por nenhum dos formatos">
  Quando a recusa chegou depois que ferramentas de servidor já haviam sido executadas dentro da solicitação, o token só pode ser resgatado continuando a resposta parcial. Essa restrição é o que impede que as chamadas de ferramentas concluídas sejam executadas, e cobradas, novamente.

  Uma combinação pode, portanto, deixar o token impossível de resgatar por qualquer dos formatos, quando ambas as condições a seguir são verdadeiras:

  * A solicitação usou `output_config.format` ou um `tool_choice` que força o uso de ferramentas. Qualquer um deles exclui o formato com mensagem de assistente anexada.
  * A recusa chegou depois que ferramentas de servidor haviam sido executadas. Isso exclui o corpo inalterado.

  Se a nova tentativa com corpo inalterado for rejeitada com um erro 400 dizendo que o token deve ser resgatado continuando a resposta parcial, descarte o token. Uma nova tentativa sem ele é processada, mas reexecuta e cobra novamente as ferramentas de servidor concluídas. Exponha o custo ou o erro ao seu chamador em vez de repetir silenciosamente.
</Accordion>

## Próximos passos

<CardGroup>
  <Card title="Recusas e fallback" icon="shield" href="https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback">
    Detecte recusas e escolha entre fallback do lado do servidor, o middleware do SDK e uma nova tentativa manual.
  </Card>

  <Card title="Cache de prompt" icon="bolt" href="https://platform.claude.com/docs/pt-BR/build-with-claude/prompt-caching">
    Como leituras de cache e gravações em cache são cobradas.
  </Card>

  <Card title="Motivos de parada e fallback" icon="code" href="https://platform.claude.com/docs/pt-BR/build-with-claude/handling-stop-reasons">
    Cada valor de `stop_reason` e como lidar com ele.
  </Card>

  <Card title="Middleware do SDK" icon="settings" href="https://platform.claude.com/docs/pt-BR/cli-sdks-libraries/middleware">
    O auxiliar do SDK que aplica o crédito de fallback automaticamente.
  </Card>
</CardGroup>
