---
title: Saídas estruturadas
url: https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs
description: Obtenha resultados JSON validados de fluxos de trabalho de agentes
featureMetadata:
  status: ga
  zdr:
    eligibility: eligible
    note: Excludes [Covered Models](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements).
  supportedModels:
    - claude-fable-5-1
    - claude-mythos-5-1
    - claude-fable-5
    - claude-mythos-5
    - claude-mythos-preview
    - claude-opus-5-5
    - claude-opus-5
    - claude-opus-4-8
    - claude-opus-4-7
    - claude-opus-4-6
    - claude-sonnet-5-5
    - claude-sonnet-5
    - claude-sonnet-4-6
    - claude-sonnet-4-5-20250929
    - claude-opus-4-5-20251101
    - claude-haiku-5-5
    - claude-haiku-4-5-20251001
  supportedPlatforms:
    Claude API: ga
    Claude Platform on AWS: ga
    Amazon Bedrock:
      availability: ga
      note: No Amazon Bedrock, as saídas estruturadas estão disponíveis na integração legada [Amazon Bedrock (Opus 4.6 e anteriores)](https://platform.claude.com/docs/pt-BR/build-with-claude/claude-on-amazon-bedrock-legacy) para Claude Opus 4.6, Claude Sonnet 4.6, Claude Sonnet 4.5, Claude Opus 4.5 e Claude Haiku 4.5, e não no [Claude no Amazon Bedrock](https://platform.claude.com/docs/pt-BR/build-with-claude/claude-in-amazon-bedrock).
    Google Cloud: ga
    Microsoft Foundry: ga
---

As "structured outputs" (saídas estruturadas) restringem as respostas do Claude para que sigam um schema específico, garantindo uma saída válida e analisável para processamento posterior. As saídas estruturadas oferecem dois recursos complementares:

* **Saídas JSON** (`output_config.format`): Obtenha a resposta do Claude em um formato JSON específico, por exemplo, para extrair dados de imagens ou texto, gerar relatórios estruturados ou formatar respostas de API. Esta página aborda as saídas JSON.
* **Uso estrito de ferramentas** (`strict: true`): Garanta a validação de schema nos nomes e entradas das ferramentas. Consulte [Uso estrito de ferramentas](https://platform.claude.com/docs/pt-BR/agents-and-tools/tool-use/strict-tool-use).

Você pode usar esses recursos de forma independente ou [juntos na mesma requisição](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#using-both-features-together).

## Por que usar saídas estruturadas

Sem saídas estruturadas, o Claude pode gerar respostas JSON malformadas ou entradas de ferramentas inválidas que quebram suas aplicações. Mesmo com prompts cuidadosos, você pode encontrar:

* Erros de análise devido a sintaxe JSON inválida
* Campos obrigatórios ausentes
* Tipos de dados inconsistentes
* Violações de schema que exigem tratamento de erros e novas tentativas

As saídas estruturadas garantem respostas em conformidade com o schema por meio de decodificação restrita:

* **Sempre válidas:** Sem mais erros de `JSON.parse()`
* **Segurança de tipos:** Tipos de campos e campos obrigatórios garantidos
* **Confiáveis:** Sem necessidade de novas tentativas por violações de schema

## Como funciona

<Steps>
  <Step title="Defina seu schema">
    Descreva a estrutura desejada como um schema JSON ou como um tipo na sua linguagem. O schema segue o JSON Schema, com algumas [limitações](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#json-schema-limitations).
  </Step>

  <Step title="Envie-o em output_config.format">
    A requisição carrega o schema em `output_config.format` com `type: "json_schema"`. Os helpers do SDK configuram isso para você.
  </Step>

  <Step title="Leia a resposta">
    O Claude retorna um JSON válido que corresponde ao seu schema no bloco de conteúdo de texto da resposta. Os helpers do SDK o analisam para o seu tipo.
  </Step>
</Steps>

## Uso

<Tabs>
  <Tab title="cURL">
    ```bash
    curl https://api.anthropic.com/v1/messages \
      -H "content-type: application/json" \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -d '{
        "model": "claude-opus-5-5",
        "max_tokens": 1024,
        "messages": [
          {
            "role": "user",
            "content": "Extract the key information from this email: John Smith (john@example.com) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm."
          }
        ],
        "output_config": {
          "format": {
            "type": "json_schema",
            "schema": {
              "type": "object",
              "properties": {
                "name": {"type": "string"},
                "email": {"type": "string"},
                "plan_interest": {"type": "string"},
                "demo_requested": {"type": "boolean"}
              },
              "required": ["name", "email", "plan_interest", "demo_requested"],
              "additionalProperties": false
            }
          }
        }
      }'
    ```

    O Claude retorna um JSON como este no bloco de conteúdo de texto da resposta:

    ```json Output
    {
      "name": "John Smith",
      "email": "john@example.com",
      "plan_interest": "Enterprise",
      "demo_requested": true
    }
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    ant messages create \
      --transform 'content.#(type=="text").text|@fromstr' \
      --format jsonl <<'YAML'
    model: claude-opus-5-5
    max_tokens: 1024
    messages:
      - role: user
        content: >-
          Extract the key information from this email: John Smith
          (john@example.com) is interested in our Enterprise plan and wants
          to schedule a demo for next Tuesday at 2pm.
    output_config:
      format:
        type: json_schema
        schema:
          type: object
          properties:
            name: {type: string}
            email: {type: string}
            plan_interest: {type: string}
            demo_requested: {type: boolean}
          required: [name, email, plan_interest, demo_requested]
          additionalProperties: false
    YAML
    ```

    Para imprimir apenas algumas propriedades da saída JSON, passe um [caminho GJSON](https://platform.claude.com/docs/pt-BR/cli-sdks-libraries/cli/using#transform-output-with-gjson) para `--transform`.

    O exemplo acima produz:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}
    ```
  </Tab>

  <Tab title="Python">
    ```python
    from pydantic import BaseModel
    # ...


    class ContactInfo(BaseModel):
        name: str
        email: str
        plan_interest: str
        demo_requested: bool


    client = Anthropic()

    response = client.messages.parse(
        model="claude-opus-5-5",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": (
                    "Extract the key information from this email: "
                    "John Smith (john@example.com) is interested in our Enterprise plan "
                    "and wants to schedule a demo for next Tuesday at 2pm."
                ),
            }
        ],
        output_format=ContactInfo,
    )

    print(response.parsed_output)
    ```

    Passe um modelo [Pydantic](https://docs.pydantic.dev/) para `client.messages.parse()`, o método recomendado, como `output_format`. O SDK transforma o schema do modelo, envia-o como `output_config.format`, valida a resposta e retorna o modelo analisado em `parsed_output`.

    O exemplo acima produz:

    ```text Output wrap
    name='John Smith' email='john@example.com' plan_interest='Enterprise' demo_requested=True
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript
    import { z } from "zod";
    import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";

    const ContactInfoSchema = z.object({
      name: z.string(),
      email: z.string(),
      plan_interest: z.string(),
      demo_requested: z.boolean()
    });

    const client = new Anthropic();

    const response = await client.messages.parse({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      messages: [
        {
          role: "user",
          content:
            "Extract the key information from this email: " +
            "John Smith (john@example.com) is interested in our Enterprise plan " +
            "and wants to schedule a demo for next Tuesday at 2pm."
        }
      ],
      output_config: { format: zodOutputFormat(ContactInfoSchema) }
    });

    // Analisado e validado automaticamente
    console.log(response.parsed_output);
    ```

    Envolva um schema [Zod](https://zod.dev/) em `zodOutputFormat()` e passe-o para `client.messages.parse()` como `output_config.format`. `zodOutputFormat()` transforma o schema, e `parse()` valida a resposta e retorna o resultado analisado em `parsed_output`, tipado para corresponder ao schema.

    O exemplo acima produz:

    ```javascript Output
    {
      name: 'John Smith',
      email: 'john@example.com',
      plan_interest: 'Enterprise',
      demo_requested: true
    }
    ```
  </Tab>

  <Tab title="C#">
    ```csharp
    using Anthropic;
    using Anthropic.Models.Messages;
    using Anthropic.Services;

    var client = new AnthropicClient();

    var response = await client.Messages.Create<ContactInfo>(new MessageCreateParams
    {
        Model = Model.ClaudeOpus5_5,
        MaxTokens = 1024,
        Messages = [new() {
            Role = Role.User,
            Content = "Extract the key information from this email: "
                + "John Smith (john@example.com) is interested in our Enterprise plan "
                + "and wants to schedule a demo for next Tuesday at 2pm."
        }],
    });

    if (response.Content.Select(block => block.Parsed()).OfType<ContactInfo>().FirstOrDefault() is { } contact)
    {
        Console.WriteLine(contact);
    }

    public record ContactInfo
    {
        public string Name { get; set; } = "";
        public string Email { get; set; } = "";
        public string PlanInterest { get; set; } = "";
        public bool DemoRequested { get; set; }
    }
    ```

    Passe uma classe ou record C# simples para a sobrecarga genérica `Create<T>()`. O SDK deriva um schema JSON do tipo, transforma-o e converte cada bloco de texto de volta para esse tipo.

    O exemplo acima produz:

    ```text Output wrap
    ContactInfo { Name = John Smith, Email = john@example.com, PlanInterest = Enterprise, DemoRequested = True }
    ```
  </Tab>

  <Tab title="Go">
    ```go
    type ContactInfo struct {
    	Name          string `json:"name"`
    	Email         string `json:"email"`
    	PlanInterest  string `json:"plan_interest"`
    	DemoRequested bool   `json:"demo_requested"`
    }

    func main() {
    	client := anthropic.NewClient()

    	var contact ContactInfo
    	_, err := client.Beta.Messages.New(context.Background(), anthropic.BetaMessageNewParams{
    		Model:     anthropic.ModelClaudeOpus5_5,
    		MaxTokens: 1024,
    		Messages: []anthropic.BetaMessageParam{
    			anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock(
    				"Extract the key information from this email: " +
    					"John Smith (john@example.com) is interested in our Enterprise plan " +
    					"and wants to schedule a demo for next Tuesday at 2pm.",
    			)),
    		},
    		OutputConfig: anthropic.BetaOutputConfigParam{
    			Format: anthropic.BetaJSONOutputFormatParam{Schema: &contact},
    		},
    	})
    	if err != nil {
    		panic(err)
    	}

    	fmt.Printf("%#v\n", contact)
    }
    ```

    <Note>
      Passar uma struct como schema está em beta no Go, então este exemplo usa `client.Beta.Messages.New`. Para usar o `client.Messages.New` GA, passe um schema JSON conforme mostrado em [Usando um schema JSON bruto](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#using-a-raw-json-schema).
    </Note>

    O SDK gera e transforma o schema JSON a partir da struct e desserializa a resposta nela.

    O exemplo acima produz:

    ```text Output wrap
    main.ContactInfo{Name:"John Smith", Email:"john@example.com", PlanInterest:"Enterprise", DemoRequested:true}
    ```
  </Tab>

  <Tab title="Java">
    ```java
    static class ContactInfo {
        public String name;
        public String email;
        public String plan_interest;
        public boolean demo_requested;
    }

    void main() throws Exception {
        AnthropicClient client = AnthropicOkHttpClient.fromEnv();

        StructuredMessageCreateParams<ContactInfo> params = MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_5_5)
            .maxTokens(1024)
            .addUserMessage("Extract the key information from this email: "
                + "John Smith (john@example.com) is interested in our Enterprise plan "
                + "and wants to schedule a demo for next Tuesday at 2pm.")
            .outputConfig(ContactInfo.class)
            .build();

        StructuredMessage<ContactInfo> response = client.messages().create(params);
        ContactInfo contact = response.content().stream()
            .flatMap(block -> block.text().stream())
            .findFirst().orElseThrow().text();
        IO.println(new ObjectMapper().writeValueAsString(contact));
    }
    ```

    Quando você passa uma classe Java para `outputConfig()`, o SDK deriva um schema JSON dela e valida o schema. O builder então produz um `StructuredMessageCreateParams<T>`. Em vez de transformar o schema, a validação local do SDK rejeita [restrições não suportadas pela API](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#json-schema-limitations). Leia o resultado analisado com `response.content().stream().flatMap(block -> block.text().stream()).findFirst().orElseThrow().text()`.

    O exemplo acima produz:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}
    ```

    <Note>
      Declare suas classes de schema como classes de nível superior ou classes aninhadas `static`. Esse requisito vem da biblioteca Jackson Databind (`com.fasterxml.jackson.databind`), que o SDK usa para desserializar respostas JSON em instâncias das suas classes e que não consegue instanciar classes internas não estáticas.
    </Note>

    <Accordion title="Apagamento de tipos genéricos">
      O Java retém informações de tipos genéricos para campos nos metadados da classe, mas o apagamento de tipos genéricos se aplica em outros escopos. Embora um schema JSON possa ser derivado de um campo `BookList.books` com tipo `List<Book>`, um schema JSON válido não pode ser derivado de uma variável local desse mesmo tipo.

      Se ocorrer um erro ao converter uma resposta JSON em uma instância de classe Java, a mensagem de erro inclui a resposta JSON para auxiliar no diagnóstico. Se sua resposta JSON puder conter informações sensíveis, evite registrá-la diretamente em logs ou certifique-se de remover quaisquer detalhes sensíveis da mensagem de erro.
    </Accordion>

    <Accordion title="Validação local de schema">
      As saídas estruturadas suportam um [subconjunto da linguagem JSON Schema](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#json-schema-limitations). O SDK gera schemas automaticamente a partir de classes para se alinhar a esse subconjunto. O método `outputConfig(Class<T>)` realiza uma verificação de validação no schema derivado da classe especificada.

      Pontos principais:

      * **A validação local** ocorre sem enviar requisições ao modelo de IA remoto.
      * **A validação remota** também é realizada pelo modelo de IA ao receber o schema JSON.
      * **Compatibilidade de versões:** A validação local pode falhar enquanto a validação remota é bem-sucedida se a versão do SDK estiver desatualizada.
      * **Desativando a validação local:** Passe `JsonSchemaLocalValidation.NO` se você encontrar problemas de compatibilidade:

      ```java
      import com.anthropic.core.JsonSchemaLocalValidation;
      // ...

      static class BookList {
          public List<String> books;
      }

      void main() {
          StructuredMessageCreateParams<BookList> createParams = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(2048)
              .outputConfig(BookList.class, JsonSchemaLocalValidation.NO)
              .addUserMessage("List some famous late twentieth century novels.")
              .build();
      }
      ```
    </Accordion>

    <Accordion title="Streaming">
      As saídas estruturadas também funcionam com streaming. Como as respostas chegam em eventos de stream, você precisa acumular a resposta completa antes de desserializar o JSON.

      Use `MessageAccumulator` para coletar as strings JSON do stream. Uma vez acumuladas, chame `MessageAccumulator.message(Class<T>)` para converter a `Message` acumulada em uma `StructuredMessage`, que desserializa automaticamente o JSON na sua classe Java.
    </Accordion>

    <Accordion title="Propriedades do schema JSON">
      Quando o SDK deriva um schema JSON das suas classes Java, ele inclui por padrão todas as propriedades representadas por campos `public` ou métodos getter `public` e exclui campos e métodos getter não `public`.

      Você pode controlar a visibilidade com anotações:

      * `@JsonIgnore` exclui um campo ou método getter `public`
      * `@JsonProperty` inclui um campo ou método getter não `public`

      Se você definir campos `private` com métodos getter `public`, o SDK deriva o nome da propriedade a partir do getter (por exemplo, o campo `private` `myValue` com o método `public` `getMyValue()` produz uma propriedade `"myValue"`). Para usar um nome de getter não convencional, anote o método com `@JsonProperty`.

      Cada classe deve definir pelo menos uma propriedade para o schema JSON. Um erro de validação ocorre se nenhum campo ou método getter puder produzir propriedades de schema, como quando:

      * Não há campos ou métodos getter na classe
      * Todos os membros `public` estão anotados com `@JsonIgnore`
      * Todos os membros não `public` não possuem anotações `@JsonProperty`
      * Um campo usa um tipo `Map`, que produz um campo `"properties"` vazio
    </Accordion>

    <Accordion title="Composição e herança">
      Suas classes Java podem usar composição e herança para compartilhar estrutura ao definir schemas JSON. Cada padrão afeta a estrutura de saída de forma diferente.

      **A composição** produz saída JSON aninhada. Derivando um schema da classe `Composed` que compõe `A` e `B`:

      ```java
      static class A {
          public String a;
      }

      static class B {
          public String b;
      }

      static class Composed {
          public A composedA;
          public B composedB;
      }
      ```

      A saída JSON tem esta estrutura aninhada:

      ```json
      {
        "composedA": { "a": "hello" },
        "composedB": { "b": "world" }
      }
      ```

      **A herança** produz saída JSON plana. Derivando um schema da classe `Derived` que estende `Base`:

      ```java
      static class Base {
          public String a;
      }

      static class Derived extends Base {
          public String b;
      }
      ```

      A saída JSON tem esta estrutura plana:

      ```json
      {
        "a": "hello",
        "b": "world"
      }
      ```
    </Accordion>

    <Accordion title="Anotações (Jackson e Swagger)">
      Você pode usar anotações do Jackson Databind para enriquecer o schema JSON derivado das suas classes Java:

      ```java
      import com.fasterxml.jackson.annotation.JsonClassDescription;
      import com.fasterxml.jackson.annotation.JsonIgnore;
      import com.fasterxml.jackson.annotation.JsonPropertyDescription;

      static class Person {

        @JsonPropertyDescription("The first name and surname of the person")
        public String name;

        public int birthYear;

        @JsonPropertyDescription("The year the person died, or 'present' if the person is living.")
        public String deathYear;
      }

      @JsonClassDescription("The details of one published book")
      static class Book {

        public String title;
        public Person author;

        @JsonPropertyDescription("The year in which the book was first published.")
        public int publicationYear;

        @JsonIgnore
        public String genre;
      }

      static class BookList {
        public List<Book> books;
      }
      ```

      Resumo das anotações:

      * `@JsonClassDescription`: Adiciona uma descrição a uma classe
      * `@JsonPropertyDescription`: Adiciona uma descrição a um campo ou método getter
      * `@JsonIgnore`: Exclui um campo ou getter `public` do schema
      * `@JsonProperty`: Inclui um campo ou getter não `public` no schema

      Se você usar `@JsonProperty(required = false)`, o SDK ignora o valor `false`. Schemas derivados de classes sempre marcam todas as propriedades como obrigatórias.

      Você também pode usar as anotações `@Schema` e `@ArraySchema` do Swagger Core (OpenAPI 3) para restrições específicas de tipo:

      ```java
      import io.swagger.v3.oas.annotations.media.ArraySchema;
      import io.swagger.v3.oas.annotations.media.Schema;

      static class Article {

        @ArraySchema(minItems = 1)
        public List<String> authors;

        public String title;

        @Schema(format = "date")
        public String publicationDate;

        public int pageCount;
      }
      ```

      A validação local verifica que você não usou nenhuma palavra-chave de restrição não suportada, mas os valores das restrições não são validados localmente. Por exemplo, um valor `"format"` não suportado pode passar na validação local, mas causar um erro remoto.

      Se você usar anotações Jackson e Swagger para definir o mesmo campo do schema, a anotação Jackson tem precedência.
    </Accordion>
  </Tab>

  <Tab title="PHP">
    ```php
    use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
    use Anthropic\Lib\Contracts\StructuredOutputModel;

    $client = new Client();

    class ContactInfo implements StructuredOutputModel
    {
        use StructuredOutputModelTrait;

        public string $name;
        public string $email;
        public string $plan_interest;
        public bool $demo_requested;
    }

    $message = $client->messages->create(
        maxTokens: 1024,
        messages: [
            [
                'role' => 'user',
                'content' => 'Extract the key information from this email: '
                    . 'John Smith (john@example.com) is interested in our Enterprise plan '
                    . 'and wants to schedule a demo for next Tuesday at 2pm.',
            ],
        ],
        model: 'claude-opus-5-5',
        outputConfig: ['format' => ContactInfo::class],
    );

    $contact = $message->parsedOutput();
    if ($contact instanceof ContactInfo) {
        var_dump($contact);
    }
    ```

    Defina uma classe que implemente `StructuredOutputModel` e use `StructuredOutputModelTrait`, e passe seu nome em `outputConfig: ['format' => MyClass::class]`. O SDK deriva um schema JSON dos tipos de propriedade PHP 8 da classe, transforma-o e retorna uma instância tipada de `$message->parsedOutput()`.

    `parsedOutput()` retorna a instância do seu modelo em caso de sucesso, ou `null` (ou um array de erro) se a análise falhar. Use `instanceof` para restringir o tipo antes de acessar os campos.

    O exemplo acima produz:

    ```text Output wrap
    object(ContactInfo)#42 (4) {
      ["name"]=>
      string(10) "John Smith"
      ["email"]=>
      string(16) "john@example.com"
      ["plan_interest"]=>
      string(10) "Enterprise"
      ["demo_requested"]=>
      bool(true)
    }
    ```

    <Accordion title="Inferência de tipos">
      O SDK mapeia os tipos de propriedade nativos do PHP 8 para JSON Schema:

      | Tipo PHP                                      | JSON Schema                      |
      | --------------------------------------------- | -------------------------------- |
      | `string`                                      | `"string"`                       |
      | `int`                                         | `"integer"`                      |
      | `float`                                       | `"number"`                       |
      | `bool`                                        | `"boolean"`                      |
      | `array`                                       | `"array"` (veja a nota a seguir) |
      | `?type` (anulável)                            | Campo opcional                   |
      | Classe que implementa `StructuredOutputModel` | Objeto aninhado                  |

      Para propriedades `array`, o SDK adiciona um schema `items` somente quando o tipo do elemento é um `StructuredOutputModel` aninhado, declarado com `#[Constrained(itemClass: MyModel::class)]` ou um docblock `/** @var MyModel[] */`. Arrays de escalares (`string[]`, `int[]`) emitem um `{"type":"array"}` sem restrições.

      Todas as propriedades não anuláveis se tornam campos obrigatórios.
    </Accordion>

    <Accordion title="Restrições com o atributo #[Constrained]">
      Adicione restrições com o atributo `#[Constrained]`:

      ```php
      use Anthropic\Lib\Attributes\Constrained;
      use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
      use Anthropic\Lib\Contracts\StructuredOutputModel;

      class Address implements StructuredOutputModel { use StructuredOutputModelTrait; public string $street; }

      class Profile implements StructuredOutputModel
      {
          use StructuredOutputModelTrait;

          #[Constrained(description: 'Age in years', minimum: 0, maximum: 150)]
          public int $age;

          #[Constrained(format: 'email')]
          public string $email;

          #[Constrained(itemClass: Address::class, minItems: 1)]
          public array $addresses;
      }
      ```

      **Restrições aplicadas pela API** (enviadas no schema): `description`, `format`, `const`, `itemClass`, `minItems` (somente 0 ou 1).

      **Restrições validadas pelo SDK** (removidas do schema enviado, anexadas à descrição e validadas em relação à resposta): `minimum`, `maximum`, `multipleOf`, `minLength`, `maxLength`.
    </Accordion>
  </Tab>

  <Tab title="Ruby">
    ```ruby
    client = Anthropic::Client.new

    class ContactInfo < Anthropic::BaseModel
      required :name, String
      required :email, String
      required :plan_interest, String
      required :demo_requested, Anthropic::Boolean
    end

    message = client.messages.create(
      model: "claude-opus-5-5",
      max_tokens: 1024,
      messages: [{
        role: "user",
        content: "Extract the key information from this email: " \
          "John Smith (john@example.com) is interested in our Enterprise plan " \
          "and wants to schedule a demo for next Tuesday at 2pm."
      }],
      output_config: {format: ContactInfo}
    )

    contact = message.parsed_output
    puts contact
    ```

    Defina uma classe que estenda `Anthropic::BaseModel` e passe-a para `messages.create()` como `output_config: {format: Model}`. O SDK deriva um schema JSON da classe, transforma-o e atribui o resultado analisado ao atributo `parsed_output` da resposta como um objeto Ruby tipado.

    O exemplo acima produz:

    ```text Output wrap
    {name: "John Smith", email: "john@example.com", plan_interest: "Enterprise", demo_requested: true}
    ```

    <Accordion title="Recursos avançados de modelo">
      O SDK Ruby suporta recursos adicionais de definição de modelo para schemas mais ricos:

      * **Palavra-chave `doc:`:** Adicione descrições aos campos para uma saída de schema mais informativa
      * **`Anthropic::ArrayOf[T]`:** Arrays tipados. Passe restrições no nível do array (`min_items:`, `max_items:`) como palavras-chave em `required`/`optional`, não no próprio `ArrayOf`
      * **`Anthropic::EnumOf[:a, :b]`:** Campos enum com valores restritos
      * **`Anthropic::UnionOf[T1, T2]`:** Tipos união mapeados para `anyOf`

      ```ruby
      class FamousNumber < Anthropic::BaseModel
        required :value, Float
        optional :reason, String, doc: "why is this number mathematically significant?"
      end

      class Output < Anthropic::BaseModel
        required :numbers, Anthropic::ArrayOf[FamousNumber], min_items: 3, max_items: 5
      end

      message = client.messages.create(
        model: "claude-opus-5-5",
        max_tokens: 1024,
        messages: [{role: "user", content: "give me some famous numbers"}],
        output_config: {format: Output}
      )

      message.parsed_output
      # => #<Output numbers=[#<FamousNumber value=3.14159... reason="Pi é...">...]>
      ```
    </Accordion>
  </Tab>
</Tabs>

## Como funciona a transformação do SDK

A maioria dos helpers do SDK transforma schemas que usam recursos não suportados. As etapas da transformação:

1. **Remover restrições não suportadas** (por exemplo, `minimum`, `maximum`, `minLength`, `maxLength`)
2. **Atualizar descrições** adicionando cada restrição não suportada à descrição do campo (por exemplo, `{minimum: 100}`)
3. **Adicionar `additionalProperties: false`** a todos os objetos
4. **Filtrar formatos de string** apenas para a lista suportada
5. **Validar respostas** em relação ao seu schema original e todas as suas restrições, se o helper validar respostas

O Claude recebe um schema simplificado, mas um helper que valida respostas ainda aplica todas as restrições no seu código.

**Exemplo:** Um campo com `minimum: 100` se torna um inteiro simples no schema enviado, e o SDK adiciona `{minimum: 100}` à descrição do campo. Um helper que valida respostas ainda verifica a resposta em relação a `minimum: 100`.

## Usando um schema JSON bruto

Para usar um schema JSON de um arquivo, de uma especificação OpenAPI ou de código que o constrói em tempo de execução, passe-o em `output_config.format`.

<Tabs>
  <Tab title="cURL">
    ```bash
    curl https://api.anthropic.com/v1/messages \
      -H "content-type: application/json" \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -d '{
        "model": "claude-opus-5-5",
        "max_tokens": 1024,
        "messages": [
          {
            "role": "user",
            "content": "Extract the key information from this email: John Smith (john@example.com) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm."
          }
        ],
        "output_config": {
          "format": {
            "type": "json_schema",
            "schema": {
              "type": "object",
              "properties": {
                "name": {"type": "string"},
                "email": {"type": "string"},
                "plan_interest": {"type": "string"},
                "demo_requested": {"type": "boolean"}
              },
              "required": ["name", "email", "plan_interest", "demo_requested"],
              "additionalProperties": false
            }
          }
        }
      }'
    ```

    O Claude retorna um JSON como este no bloco de conteúdo de texto da resposta:

    ```json Output
    {
      "name": "John Smith",
      "email": "john@example.com",
      "plan_interest": "Enterprise",
      "demo_requested": true
    }
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    ant messages create \
      --transform 'content.#(type=="text").text|@fromstr' \
      --format jsonl <<'YAML'
    model: claude-opus-5-5
    max_tokens: 1024
    messages:
      - role: user
        content: >-
          Extract the key information from this email: John Smith
          (john@example.com) is interested in our Enterprise plan and wants
          to schedule a demo for next Tuesday at 2pm.
    output_config:
      format:
        type: json_schema
        schema:
          type: object
          properties:
            name: {type: string}
            email: {type: string}
            plan_interest: {type: string}
            demo_requested: {type: boolean}
          required: [name, email, plan_interest, demo_requested]
          additionalProperties: false
    YAML
    ```

    O exemplo acima produz:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}
    ```
  </Tab>

  <Tab title="Python">
    ```python
    client = anthropic.Anthropic()

    response = client.messages.create(
        model="claude-opus-5-5",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": (
                    "Extract the key information from this email: "
                    "John Smith (john@example.com) is interested in our Enterprise plan "
                    "and wants to schedule a demo for next Tuesday at 2pm."
                ),
            }
        ],
        output_config={
            "format": {
                "type": "json_schema",
                "schema": {
                    "type": "object",
                    "properties": {
                        "name": {"type": "string"},
                        "email": {"type": "string"},
                        "plan_interest": {"type": "string"},
                        "demo_requested": {"type": "boolean"},
                    },
                    "required": ["name", "email", "plan_interest", "demo_requested"],
                    "additionalProperties": False,
                },
            }
        },
    )
    text = next(block.text for block in response.content if block.type == "text")
    contact = json.loads(text)
    print(contact)
    ```

    O exemplo acima produz:

    ```text Output wrap
    {'name': 'John Smith', 'email': 'john@example.com', 'plan_interest': 'Enterprise', 'demo_requested': True}
    ```

    Para mover [restrições não suportadas pela API](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#json-schema-limitations) para as descrições dos campos, passe o schema por `transform_schema()` do pacote `anthropic` antes de enviá-lo e edite o resultado se necessário. `transform_schema()` também aceita um modelo Pydantic. Diferentemente de `client.messages.parse()`, ele retorna o schema transformado em vez de enviá-lo.
  </Tab>

  <Tab title="TypeScript">
    ```typescript
    import { jsonSchemaOutputFormat } from "@anthropic-ai/sdk/helpers/json-schema";

    const client = new Anthropic();

    const response = await client.messages.parse({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      messages: [
        {
          role: "user",
          content: "Extract contact info: John Smith, john@example.com, interested in the Pro plan"
        }
      ],
      output_config: {
        format: jsonSchemaOutputFormat({
          type: "object",
          properties: {
            name: { type: "string" },
            email: { type: "string" },
            planInterest: { type: "string" }
          },
          required: ["name", "email", "planInterest"],
          additionalProperties: false
        } as const)
      }
    });

    // response.parsed_output é tipado como { name: string; email: string; planInterest: string } | null
    console.log(response.parsed_output);
    ```

    Use `jsonSchemaOutputFormat()` para passar um schema JSON simples para `parse()`, sem instalar o Zod. A API retorna uma resposta que está em conformidade com o schema e, se você declarar o schema com `as const`, o tipo de `parsed_output` é inferido automaticamente pelo TypeScript de acordo com seu schema. Para um schema importado ou gerado, `parsed_output` é tipado como `unknown`.

    Por padrão, o helper [transforma o schema](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#how-sdk-transformation-works) da mesma forma que `zodOutputFormat()`. Passe `{ transform: false }` como segundo argumento para enviá-lo sem alterações. Diferentemente de `zodOutputFormat()`, ele não valida a resposta, portanto não detectará violações de [restrições não suportadas pela API](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#json-schema-limitations), como `minimum`.

    O exemplo acima produz:

    ```javascript Output
    { name: 'John Smith', email: 'john@example.com', planInterest: 'Pro' }
    ```
  </Tab>

  <Tab title="C#">
    ```csharp
    using System.Text.Json;
    using Anthropic;
    using Anthropic.Models.Messages;

    var client = new AnthropicClient();

    var response = await client.Messages.Create(new MessageCreateParams
    {
        Model = Model.ClaudeOpus5_5,
        MaxTokens = 1024,
        Messages = [new() {
            Role = Role.User,
            Content = "Extract the key information from this email: "
                + "John Smith (john@example.com) is interested in our Enterprise plan "
                + "and wants to schedule a demo for next Tuesday at 2pm."
        }],
        OutputConfig = new OutputConfig
        {
            Format = new JsonOutputFormat
            {
                Schema = new Dictionary<string, JsonElement>
                {
                    ["type"] = JsonSerializer.SerializeToElement("object"),
                    ["properties"] = JsonSerializer.SerializeToElement(new
                    {
                        name = new { type = "string" },
                        email = new { type = "string" },
                        plan_interest = new { type = "string" },
                        demo_requested = new { type = "boolean" },
                    }),
                    ["required"] = JsonSerializer.SerializeToElement(
                        new[] { "name", "email", "plan_interest", "demo_requested" }),
                    ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
                },
            },
        },
    });

    if (response.Content.Select(b => b.Value).OfType<TextBlock>().FirstOrDefault() is { } textBlock)
    {
        // O JSON tem garantia de corresponder ao schema
        var contact = JsonSerializer.Deserialize<JsonElement>(textBlock.Text);
        Console.WriteLine(contact);
    }
    ```

    O exemplo acima produz:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}
    ```
  </Tab>

  <Tab title="Go">
    ```go
    type ContactInfo struct {
    	Name          string `json:"name"`
    	Email         string `json:"email"`
    	PlanInterest  string `json:"plan_interest"`
    	DemoRequested bool   `json:"demo_requested"`
    }

    func main() {
    	client := anthropic.NewClient()

    	message, _ := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
    		Model:     anthropic.ModelClaudeOpus5_5,
    		MaxTokens: 1024,
    		Messages: []anthropic.MessageParam{
    			anthropic.NewUserMessage(anthropic.NewTextBlock(
    				"Extract the key information from this email: " +
    					"John Smith (john@example.com) is interested in our Enterprise plan " +
    					"and wants to schedule a demo for next Tuesday at 2pm.",
    			)),
    		},
    		OutputConfig: anthropic.OutputConfigParam{
    			Format: anthropic.JSONOutputFormatParam{
    				Schema: map[string]any{
    					"type": "object",
    					"properties": map[string]any{
    						"name":           map[string]string{"type": "string"},
    						"email":          map[string]string{"type": "string"},
    						"plan_interest":  map[string]string{"type": "string"},
    						"demo_requested": map[string]string{"type": "boolean"},
    					},
    					"required":             []string{"name", "email", "plan_interest", "demo_requested"},
    					"additionalProperties": false,
    				},
    			},
    		},
    	})

    	for _, block := range message.Content {
    		switch variant := block.AsAny().(type) {
    		case anthropic.TextBlock:
    			var contact ContactInfo
    			json.Unmarshal([]byte(variant.Text), &contact)
    			fmt.Printf("%#v\n", contact)
    		}
    	}
    }
    ```

    O exemplo acima produz:

    ```text Output wrap
    main.ContactInfo{Name:"John Smith", Email:"john@example.com", PlanInterest:"Enterprise", DemoRequested:true}
    ```

    Para que o SDK transforme um schema em map, passe-o por `BetaJSONSchemaOutputFormat()` na API beta.
  </Tab>

  <Tab title="Java">
    ```java
    import com.anthropic.core.JsonValue;
    import com.anthropic.models.messages.JsonOutputFormat;
    // ...
    import com.anthropic.models.messages.OutputConfig;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;

    void main() throws Exception {
        AnthropicClient client = AnthropicOkHttpClient.fromEnv();

        JsonOutputFormat.Schema schema = JsonOutputFormat.Schema.builder()
            .putAdditionalProperty("type", JsonValue.from("object"))
            .putAdditionalProperty("properties", JsonValue.from(Map.of(
                "name", Map.of("type", "string"),
                "email", Map.of("type", "string"),
                "plan_interest", Map.of("type", "string"))))
            .putAdditionalProperty("required", JsonValue.from(
                List.of("name", "email", "plan_interest")))
            .putAdditionalProperty("additionalProperties", JsonValue.from(false))
            .build();

        OutputConfig outputConfig = OutputConfig.builder()
            .format(JsonOutputFormat.builder().schema(schema).build())
            .build();

        MessageCreateParams createParams = MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_5_5)
            .maxTokens(1024)
            .outputConfig(outputConfig)
            .addUserMessage(
                "John Smith (john@example.com) is interested in our Enterprise plan.")
            .build();

        String json = client.messages().create(createParams).content().stream()
            .flatMap(contentBlock -> contentBlock.text().stream())
            .findFirst()
            .orElseThrow()
            .text();

        JsonNode contact = new ObjectMapper().readTree(json);
        IO.println(contact);
    }
    ```

    O exemplo acima produz:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise"}
    ```

    Para um exemplo mais extenso que constrói um schema aninhado com arrays e descrições, consulte [`StructuredOutputsRawExample.java`](https://github.com/anthropics/anthropic-sdk-java/blob/main/anthropic-java-example/src/main/java/com/anthropic/example/StructuredOutputsRawExample.java) no repositório do SDK.
  </Tab>

  <Tab title="PHP">
    ```php
    use Anthropic\Messages\OutputConfig;
    use Anthropic\Messages\JSONOutputFormat;

    $client = new Client();

    $message = $client->messages->create(
        maxTokens: 1024,
        messages: [
            [
                'role' => 'user',
                'content' => 'Extract the key information from this email: '
                    . 'John Smith (john@example.com) is interested in our Enterprise plan.',
            ],
        ],
        model: 'claude-opus-5-5',
        outputConfig: OutputConfig::with(format: JSONOutputFormat::with(schema: [
            'type' => 'object',
            'properties' => [
                'name' => ['type' => 'string'],
                'email' => ['type' => 'string'],
                'plan_interest' => ['type' => 'string'],
            ],
            'required' => ['name', 'email', 'plan_interest'],
            'additionalProperties' => false,
        ])),
    );

    $textBlock = array_find($message->content, static fn ($block): bool => $block->type === 'text');
    $contact = json_decode($textBlock->text, associative: true);
    var_dump($contact);
    ```

    Passe o schema como um array associativo para `OutputConfig::with()` e decodifique a resposta com `json_decode()`.

    O exemplo acima produz:

    ```text Output wrap
    array(3) {
      ["name"]=>
      string(10) "John Smith"
      ["email"]=>
      string(16) "john@example.com"
      ["plan_interest"]=>
      string(10) "Enterprise"
    }
    ```
  </Tab>

  <Tab title="Ruby">
    ```ruby
    client = Anthropic::Client.new

    response = client.messages.create(
      model: "claude-opus-5-5",
      max_tokens: 1024,
      messages: [
        {
          role: "user",
          content: "Extract the key information from this email: " \
            "John Smith (john@example.com) is interested in our Enterprise plan " \
            "and wants to schedule a demo for next Tuesday at 2pm."
        }
      ],
      output_config: {
        format: {
          type: "json_schema",
          schema: {
            type: "object",
            properties: {
              name: { type: "string" },
              email: { type: "string" },
              plan_interest: { type: "string" },
              demo_requested: { type: "boolean" }
            },
            required: ["name", "email", "plan_interest", "demo_requested"],
            additionalProperties: false
          }
        }
      }
    )

    text = response.content.find { it.type == :text }.text
    contact = JSON.parse(text)
    p contact
    ```

    O exemplo acima produz:

    ```text Output wrap
    {"name" => "John Smith", "email" => "john@example.com", "plan_interest" => "Enterprise", "demo_requested" => true}
    ```
  </Tab>
</Tabs>

## Casos de uso comuns

<AccordionGroup>
  <Accordion title="Extração de dados">
    Extraia dados estruturados de texto não estruturado:

    <CodeGroup>
      ```bash cURL
      curl https://api.anthropic.com/v1/messages \
        -H "content-type: application/json" \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -d '{
          "model": "claude-opus-5-5",
          "max_tokens": 4096,
          "messages": [
            {
              "role": "user",
              "content": "Extract invoice data from: Invoice #12345, Date: 2024-01-15, Total: $500.00"
            }
          ],
          "output_config": {
            "format": {
              "type": "json_schema",
              "schema": {
                "type": "object",
                "properties": {
                  "invoice_number": {"type": "string"},
                  "date": {"type": "string"},
                  "total_amount": {"type": "number"},
                  "line_items": {
                    "type": "array",
                    "items": {"type": "object", "additionalProperties": false}
                  },
                  "customer_name": {"type": "string"}
                },
                "required": ["invoice_number", "date", "total_amount", "line_items", "customer_name"],
                "additionalProperties": false
              }
            }
          }
        }'
      ```

      ```bash CLI
      ant messages create \
        --transform 'content.#(type=="text").text|@fromstr' \
        --format jsonl <<'YAML'
      model: claude-opus-5-5
      max_tokens: 4096
      messages:
        - role: user
          content: "Extract invoice data from: Invoice #12345, Date: 2024-01-15, Total: $500.00"
      output_config:
        format:
          type: json_schema
          schema:
            type: object
            properties:
              invoice_number: {type: string}
              date: {type: string}
              total_amount: {type: number}
              line_items:
                type: array
                items: {type: object, additionalProperties: false}
              customer_name: {type: string}
            required: [invoice_number, date, total_amount, line_items, customer_name]
            additionalProperties: false
      YAML
      ```

      ```python Python
      from pydantic import BaseModel


      class Invoice(BaseModel):
          invoice_number: str
          date: str
          total_amount: float
          line_items: list[dict]
          customer_name: str


      client = anthropic.Anthropic()
      invoice_text = "Invoice #12345, Date: 2024-01-15, Total: $500.00"

      response = client.messages.parse(
          model="claude-opus-5-5",
          max_tokens=4096,
          output_format=Invoice,
          messages=[
              {"role": "user", "content": f"Extract invoice data from: {invoice_text}"}
          ],
      )

      print(response.parsed_output)
      ```

      ```typescript TypeScript
      import { z } from "zod";
      import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";

      const client = new Anthropic();

      const InvoiceSchema = z.object({
        invoice_number: z.string(),
        date: z.string(),
        total_amount: z.number(),
        line_items: z.array(z.record(z.string(), z.any())),
        customer_name: z.string()
      });

      const invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";
      const response = await client.messages.parse({
        model: "claude-opus-5-5",
        max_tokens: 4096,
        output_config: { format: zodOutputFormat(InvoiceSchema) },
        messages: [{ role: "user", content: `Extract invoice data from: ${invoiceText}` }]
      });
      console.log(response.parsed_output);
      ```

      ```csharp C#
      AnthropicClient client = new();

      string invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";

      var parameters = new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 4096,
          OutputConfig = new OutputConfig
          {
              Format = new JsonOutputFormat
              {
                  Schema = new Dictionary<string, JsonElement>
                  {
                      ["type"] = JsonSerializer.SerializeToElement("object"),
                      ["properties"] = JsonSerializer.SerializeToElement(new
                      {
                          invoice_number = new { type = "string" },
                          date = new { type = "string" },
                          total_amount = new { type = "number" },
                          line_items = new
                          {
                              type = "array",
                              items = new
                              {
                                  type = "object",
                                  additionalProperties = false,
                              },
                          },
                          customer_name = new { type = "string" },
                      }),
                      ["required"] = JsonSerializer.SerializeToElement(new[] { "invoice_number", "date", "total_amount", "line_items", "customer_name" }),
                      ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
                  },
              },
          },
          Messages = [new() { Role = Role.User, Content = $"Extract invoice data from: {invoiceText}" }]
      };

      var message = await client.Messages.Create(parameters);
      Console.WriteLine(message);
      ```

      ```go Go
      client := anthropic.NewClient()

      invoiceText := "Invoice #12345, Date: 2024-01-15, Total: $500.00"

      schema := map[string]any{
      	"type":                 "object",
      	"additionalProperties": false,
      	"properties": map[string]any{
      		"invoice_number": map[string]any{"type": "string"},
      		"date":           map[string]any{"type": "string"},
      		"total_amount":   map[string]any{"type": "number"},
      		"line_items": map[string]any{
      			"type": "array",
      			"items": map[string]any{
      				"type":                 "object",
      				"additionalProperties": false,
      				"properties": map[string]any{
      					"description": map[string]any{"type": "string"},
      					"quantity":    map[string]any{"type": "number"},
      					"unit_price":  map[string]any{"type": "number"},
      				},
      				"required": []string{"description", "quantity", "unit_price"},
      			},
      		},
      		"customer_name": map[string]any{"type": "string"},
      	},
      	"required": []string{"invoice_number", "date", "total_amount", "line_items", "customer_name"},
      }

      response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
      	Model:     anthropic.ModelClaudeOpus5_5,
      	MaxTokens: 4096,
      	OutputConfig: anthropic.OutputConfigParam{
      		Format: anthropic.JSONOutputFormatParam{
      			Schema: schema,
      		},
      	},
      	Messages: []anthropic.MessageParam{
      		anthropic.NewUserMessage(anthropic.NewTextBlock(fmt.Sprintf("Extract invoice data from: %s", invoiceText))),
      	},
      })
      if err != nil {
      	log.Fatal(err)
      }
      for _, block := range response.Content {
      	switch variant := block.AsAny().(type) {
      	case anthropic.TextBlock:
      		fmt.Println(variant.Text)
      	}
      }
      ```

      ```java Java
      import com.fasterxml.jackson.annotation.JsonProperty;

      static class LineItem {
          @JsonProperty("description")
          public String description;

          @JsonProperty("quantity")
          public int quantity;

          @JsonProperty("unit_price")
          public double unitPrice;
      }

      static class Invoice {
          @JsonProperty("invoice_number")
          public String invoiceNumber;

          @JsonProperty("date")
          public String date;

          @JsonProperty("total_amount")
          public double totalAmount;

          @JsonProperty("line_items")
          public List<LineItem> lineItems;

          @JsonProperty("customer_name")
          public String customerName;
      }

      void main() {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          String invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";

          StructuredMessageCreateParams<Invoice> params = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(4096L)
              .outputConfig(Invoice.class)
              .addUserMessage("Extract invoice data from: " + invoiceText)
              .build();

          StructuredMessage<Invoice> response = client.messages().create(params);
          Invoice invoice = response.content().stream()
              .flatMap(block -> block.text().stream())
              .findFirst().orElseThrow().text();
          IO.println(invoice.invoiceNumber + ": $" + invoice.totalAmount);
      }
      ```

      ```php PHP
      use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
      use Anthropic\Lib\Contracts\StructuredOutputModel;

      $client = new Client();

      class Invoice implements StructuredOutputModel
      {
          use StructuredOutputModelTrait;

          public string $invoice_number;
          public string $date;
          public float $total_amount;
          public array $line_items;
          public string $customer_name;
      }

      $invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";

      $message = $client->messages->create(
          maxTokens: 4096,
          messages: [
              ['role' => 'user', 'content' => "Extract invoice data from: $invoiceText"]
          ],
          model: 'claude-opus-5-5',
          outputConfig: ['format' => Invoice::class],
      );

      $invoice = $message->parsedOutput();
      if ($invoice instanceof Invoice) {
          echo "Invoice {$invoice->invoice_number}: \${$invoice->total_amount}\n";
      }
      ```

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

      class LineItem < Anthropic::BaseModel
        required :description, String
        required :amount, Float
      end

      class Invoice < Anthropic::BaseModel
        required :invoice_number, String
        required :date, String
        required :total_amount, Float
        required :line_items, Anthropic::ArrayOf[LineItem]
        required :customer_name, String
      end

      invoice_text = "Invoice #12345, Date: 2024-01-15, Total: $500.00"

      message = client.messages.create(
        model: "claude-opus-5-5",
        max_tokens: 4096,
        output_config: {format: Invoice},
        messages: [
          {role: "user", content: "Extract invoice data from: #{invoice_text}"}
        ]
      )

      invoice = message.parsed_output
      puts "Invoice #{invoice.invoice_number}: $#{invoice.total_amount}"
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Classificação">
    Classifique conteúdo com categorias estruturadas:

    <CodeGroup>
      ```bash cURL
      curl https://api.anthropic.com/v1/messages \
        -H "content-type: application/json" \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -d '{
          "model": "claude-opus-5-5",
          "max_tokens": 1024,
          "messages": [
            {
              "role": "user",
              "content": "Classify this feedback: Great product, fast shipping!"
            }
          ],
          "output_config": {
            "format": {
              "type": "json_schema",
              "schema": {
                "type": "object",
                "properties": {
                  "category": {"type": "string"},
                  "confidence": {"type": "number"},
                  "tags": {"type": "array", "items": {"type": "string"}},
                  "sentiment": {"type": "string"}
                },
                "required": ["category", "confidence", "tags", "sentiment"],
                "additionalProperties": false
              }
            }
          }
        }'
      ```

      ```bash CLI
      ant messages create \
        --transform 'content.#(type=="text").text|@fromstr' \
        --format jsonl <<'YAML'
      model: claude-opus-5-5
      max_tokens: 1024
      messages:
        - role: user
          content: "Classify this feedback: Great product, fast shipping!"
      output_config:
        format:
          type: json_schema
          schema:
            type: object
            properties:
              category:
                type: string
              confidence:
                type: number
              tags:
                type: array
                items:
                  type: string
              sentiment:
                type: string
            required:
              - category
              - confidence
              - tags
              - sentiment
            additionalProperties: false
      YAML
      ```

      ```python Python
      from pydantic import BaseModel

      client = Anthropic()


      class Classification(BaseModel):
          category: str
          confidence: float
          tags: list[str]
          sentiment: str


      feedback_text = "Great product, but the delivery was slow."
      response = client.messages.parse(
          model="claude-opus-5-5",
          max_tokens=1024,
          output_format=Classification,
          messages=[{"role": "user", "content": f"Classify this feedback: {feedback_text}"}],
      )

      print(response.parsed_output)
      ```

      ```typescript TypeScript
      import { z } from "zod";
      import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";

      const client = new Anthropic();

      const ClassificationSchema = z.object({
        category: z.string(),
        confidence: z.number(),
        tags: z.array(z.string()),
        sentiment: z.string()
      });

      const feedbackText = "Great product, but the delivery was slow.";
      const response = await client.messages.parse({
        model: "claude-opus-5-5",
        max_tokens: 1024,
        output_config: { format: zodOutputFormat(ClassificationSchema) },
        messages: [{ role: "user", content: `Classify this feedback: ${feedbackText}` }]
      });

      console.log(response.parsed_output);
      ```

      ```csharp C#
      string feedbackText = "Great product, fast shipping!";

      var parameters = new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 1024,
          Messages = [new() { Role = Role.User, Content = $"Classify this feedback: {feedbackText}" }],
          OutputConfig = new OutputConfig
          {
              Format = new JsonOutputFormat
              {
                  Schema = new Dictionary<string, JsonElement>
                  {
                      ["type"] = JsonSerializer.SerializeToElement("object"),
                      ["properties"] = JsonSerializer.SerializeToElement(new
                      {
                          category = new { type = "string" },
                          confidence = new { type = "number" },
                          tags = new { type = "array", items = new { type = "string" } },
                          sentiment = new { type = "string" },
                      }),
                      ["required"] = JsonSerializer.SerializeToElement(new[] { "category", "confidence", "tags", "sentiment" }),
                      ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
                  },
              },
          },
      };

      var message = await client.Messages.Create(parameters);
      Console.WriteLine(message);
      ```

      ```go Go
      feedbackText := "Great product, fast shipping!"

      schema := map[string]any{
      	"type": "object",
      	"properties": map[string]any{
      		"category":   map[string]any{"type": "string"},
      		"confidence": map[string]any{"type": "number"},
      		"tags":       map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
      		"sentiment":  map[string]any{"type": "string"},
      	},
      	"required":             []string{"category", "confidence", "tags", "sentiment"},
      	"additionalProperties": false,
      }

      response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
      	Model:     anthropic.ModelClaudeOpus5_5,
      	MaxTokens: 1024,
      	OutputConfig: anthropic.OutputConfigParam{
      		Format: anthropic.JSONOutputFormatParam{
      			Schema: schema,
      		},
      	},
      	Messages: []anthropic.MessageParam{
      		anthropic.NewUserMessage(anthropic.NewTextBlock(fmt.Sprintf("Classify this feedback: %s", feedbackText))),
      	},
      })
      if err != nil {
      	log.Fatal(err)
      }
      for _, block := range response.Content {
      	switch variant := block.AsAny().(type) {
      	case anthropic.TextBlock:
      		var result map[string]any
      		json.Unmarshal([]byte(variant.Text), &result)
      		fmt.Println(result)
      	}
      }
      ```

      ```java Java
      import com.fasterxml.jackson.annotation.JsonProperty;

      static class Classification {
          @JsonProperty("category")
          public String category;

          @JsonProperty("confidence")
          public double confidence;

          @JsonProperty("tags")
          public List<String> tags;

          @JsonProperty("sentiment")
          public String sentiment;
      }

      void main() {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          String feedbackText = "Great product, fast shipping!";

          StructuredMessageCreateParams<Classification> params = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024L)
              .outputConfig(Classification.class)
              .addUserMessage("Classify this feedback: " + feedbackText)
              .build();

          StructuredMessage<Classification> response = client.messages().create(params);
          Classification result = response.content().stream()
              .flatMap(block -> block.text().stream())
              .findFirst().orElseThrow().text();
          IO.println(result.category + " (" + result.confidence + ")");
      }
      ```

      ```php PHP
      use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
      use Anthropic\Lib\Contracts\StructuredOutputModel;

      $client = new Client();

      class Classification implements StructuredOutputModel
      {
          use StructuredOutputModelTrait;

          public string $category;
          public float $confidence;
          public array $tags;
          public string $sentiment;
      }

      $feedbackText = "Great product, fast shipping!";

      $message = $client->messages->create(
          maxTokens: 1024,
          messages: [
              ['role' => 'user', 'content' => "Classify this feedback: {$feedbackText}"]
          ],
          model: 'claude-opus-5-5',
          outputConfig: ['format' => Classification::class],
      );

      $result = $message->parsedOutput();
      if ($result instanceof Classification) {
          echo "{$result->category} ({$result->confidence}): {$result->sentiment}\n";
      }
      ```

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

      class Classification < Anthropic::BaseModel
        required :category, String
        required :confidence, Float
        required :tags, Anthropic::ArrayOf[String]
        required :sentiment, String
      end

      feedback_text = "Great product, fast shipping!"

      message = client.messages.create(
        model: "claude-opus-5-5",
        max_tokens: 1024,
        output_config: {format: Classification},
        messages: [
          {role: "user", content: "Classify this feedback: #{feedback_text}"}
        ]
      )
      puts message.parsed_output
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Formatação de respostas de API">
    Gere respostas prontas para API:

    <CodeGroup>
      ```bash cURL
      curl https://api.anthropic.com/v1/messages \
        -H "content-type: application/json" \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -d '{
          "model": "claude-opus-5-5",
          "max_tokens": 1024,
          "messages": [
            {
              "role": "user",
              "content": "Process this request: ..."
            }
          ],
          "output_config": {
            "format": {
              "type": "json_schema",
              "schema": {
                "type": "object",
                "properties": {
                  "status": {"type": "string"},
                  "data": {"type": "object", "additionalProperties": false},
                  "errors": {
                    "type": "array",
                    "items": {"type": "object", "additionalProperties": false}
                  },
                  "metadata": {"type": "object", "additionalProperties": false}
                },
                "required": ["status", "data", "metadata"],
                "additionalProperties": false
              }
            }
          }
        }'
      ```

      ```bash CLI
      ant messages create \
        --transform 'content.#(type=="text").text' \
        --raw-output <<'YAML'
      model: claude-opus-5-5
      max_tokens: 1024
      output_config:
        format:
          type: json_schema
          schema:
            type: object
            properties:
              status:
                type: string
              data:
                type: object
                additionalProperties: false
              errors:
                type: array
                items:
                  type: object
                  additionalProperties: false
              metadata:
                type: object
                additionalProperties: false
            required:
              - status
              - data
              - metadata
            additionalProperties: false
      messages:
        - role: user
          content: "Process this request: ..."
      YAML
      ```

      ```python Python
      from pydantic import BaseModel

      client = Anthropic()


      class APIResponse(BaseModel):
          status: str
          data: dict
          errors: list[dict] | None
          metadata: dict


      response = client.messages.parse(
          model="claude-opus-5-5",
          max_tokens=1024,
          output_format=APIResponse,
          messages=[{"role": "user", "content": "Process this request: ..."}],
      )

      print(response.parsed_output)
      ```

      ```typescript TypeScript
      import { z } from "zod";
      import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";

      const client = new Anthropic();

      const APIResponseSchema = z.object({
        status: z.string(),
        data: z.record(z.string(), z.any()),
        errors: z.array(z.record(z.string(), z.any())).optional(),
        metadata: z.record(z.string(), z.any())
      });

      const response = await client.messages.parse({
        model: "claude-opus-5-5",
        max_tokens: 1024,
        output_config: { format: zodOutputFormat(APIResponseSchema) },
        messages: [{ role: "user", content: "Process this request..." }]
      });

      console.log(response.parsed_output);
      ```

      ```csharp C#
      var parameters = new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 1024,
          Messages = [new() { Role = Role.User, Content = "Process this request: ..." }],
          OutputConfig = new OutputConfig
          {
              Format = new JsonOutputFormat
              {
                  Schema = new Dictionary<string, JsonElement>
                  {
                      ["type"] = JsonSerializer.SerializeToElement("object"),
                      ["properties"] = JsonSerializer.SerializeToElement(new
                      {
                          status = new { type = "string" },
                          data = new { type = "object", additionalProperties = false },
                          errors = new
                          {
                              type = "array",
                              items = new { type = "object", additionalProperties = false },
                          },
                          metadata = new { type = "object", additionalProperties = false },
                      }),
                      ["required"] = JsonSerializer.SerializeToElement(new[] { "status", "data", "metadata" }),
                      ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
                  },
              },
          },
      };

      var message = await client.Messages.Create(parameters);
      Console.WriteLine(message);
      ```

      ```go Go
      client := anthropic.NewClient()

      response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
      	Model:     anthropic.ModelClaudeOpus5_5,
      	MaxTokens: 1024,
      	OutputConfig: anthropic.OutputConfigParam{
      		Format: anthropic.JSONOutputFormatParam{
      			Schema: map[string]any{
      				"type":                 "object",
      				"additionalProperties": false,
      				"properties": map[string]any{
      					"status": map[string]any{
      						"type": "string",
      					},
      					"data": map[string]any{
      						"type":                 "object",
      						"additionalProperties": false,
      					},
      					"errors": map[string]any{
      						"type": "array",
      						"items": map[string]any{
      							"type":                 "object",
      							"additionalProperties": false,
      						},
      					},
      					"metadata": map[string]any{
      						"type":                 "object",
      						"additionalProperties": false,
      					},
      				},
      				"required": []string{"status", "data", "metadata"},
      			},
      		},
      	},
      	Messages: []anthropic.MessageParam{
      		anthropic.NewUserMessage(anthropic.NewTextBlock("Process this request: ...")),
      	},
      })
      if err != nil {
      	log.Fatal(err)
      }
      for _, block := range response.Content {
      	switch variant := block.AsAny().(type) {
      	case anthropic.TextBlock:
      		fmt.Println(variant.Text)
      	}
      }
      ```

      ```java Java
      import com.fasterxml.jackson.annotation.JsonProperty;

      static class APIData {
          @JsonProperty("message")
          public String message;

          @JsonProperty("resource_id")
          public String resourceId;
      }

      static class APIError {
          @JsonProperty("code")
          public String code;

          @JsonProperty("message")
          public String message;
      }

      static class APIMetadata {
          @JsonProperty("request_id")
          public String requestId;

          @JsonProperty("timestamp")
          public String timestamp;
      }

      static class APIResponse {
          @JsonProperty("status")
          public String status;

          @JsonProperty("data")
          public APIData data;

          @JsonProperty("errors")
          public List<APIError> errors;

          @JsonProperty("metadata")
          public APIMetadata metadata;
      }

      void main() {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          StructuredMessageCreateParams<APIResponse> params = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024L)
              .outputConfig(APIResponse.class)
              .addUserMessage("Process this request: ...")
              .build();

          StructuredMessage<APIResponse> response = client.messages().create(params);
          APIResponse result = response.content().stream()
              .flatMap(block -> block.text().stream())
              .findFirst().orElseThrow().text();
          IO.println(result.status);
      }
      ```

      ```php PHP
      use Anthropic\Lib\Attributes\Constrained;
      use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
      use Anthropic\Lib\Contracts\StructuredOutputModel;

      $client = new Client();

      class Payload implements StructuredOutputModel { use StructuredOutputModelTrait; public string $message; }

      class APIError implements StructuredOutputModel { use StructuredOutputModelTrait; public string $code; public string $detail; }

      class Metadata implements StructuredOutputModel { use StructuredOutputModelTrait; public string $request_id; }

      class APIResponse implements StructuredOutputModel
      {
          use StructuredOutputModelTrait;

          public string $status;
          public Payload $data;
          #[Constrained(itemClass: APIError::class)]
          public ?array $errors;
          public Metadata $metadata;
      }

      $message = $client->messages->create(
          maxTokens: 1024,
          messages: [
              ['role' => 'user', 'content' => 'Process this request: ...']
          ],
          model: 'claude-opus-5-5',
          outputConfig: ['format' => APIResponse::class],
      );

      $result = $message->parsedOutput();
      if ($result instanceof APIResponse) {
          echo "{$result->status}: {$result->data->message}\n";
      }
      ```

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

      class Payload < Anthropic::BaseModel
        required :message, String
      end

      class APIError < Anthropic::BaseModel
        required :code, String
        required :detail, String
      end

      class Metadata < Anthropic::BaseModel
        required :request_id, String
      end

      class APIResponse < Anthropic::BaseModel
        required :status, String
        required :data, Payload
        optional :errors, Anthropic::ArrayOf[APIError]
        required :metadata, Metadata
      end

      message = client.messages.create(
        model: "claude-opus-5-5",
        max_tokens: 1024,
        output_config: {format: APIResponse},
        messages: [
          {role: "user", content: "Process this request: ..."}
        ]
      )
      puts message.parsed_output
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

## Uso estrito de ferramentas

Para impor a conformidade com JSON Schema nas entradas de ferramentas com amostragem restrita por gramática, consulte [Uso estrito de ferramentas](https://platform.claude.com/docs/pt-BR/agents-and-tools/tool-use/strict-tool-use).

### Usando ambos os recursos juntos

As saídas JSON e o uso estrito de ferramentas resolvem problemas diferentes e funcionam em conjunto:

* **As saídas JSON** controlam o formato de resposta do Claude (o que o Claude diz)
* **O uso estrito de ferramentas** valida os parâmetros das ferramentas (como o Claude chama suas funções)

Quando combinados, o Claude pode chamar ferramentas com parâmetros garantidamente válidos E retornar respostas JSON estruturadas. Isso é útil para fluxos de trabalho agênticos em que você precisa tanto de chamadas de ferramentas confiáveis quanto de saídas finais estruturadas.

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "messages": [
        {
          "role": "user",
          "content": "Help me plan a trip to Paris departing May 15, 2026"
        }
      ],
      "output_config": {
        "format": {
          "type": "json_schema",
          "schema": {
            "type": "object",
            "properties": {
              "summary": {"type": "string"},
              "next_steps": {"type": "array", "items": {"type": "string"}}
            },
            "required": ["summary", "next_steps"],
            "additionalProperties": false
          }
        }
      },
      "tools": [
        {
          "name": "search_flights",
          "strict": true,
          "input_schema": {
            "type": "object",
            "properties": {
              "destination": {"type": "string"},
              "date": {"type": "string", "format": "date"}
            },
            "required": ["destination", "date"],
            "additionalProperties": false
          }
        }
      ]
    }'
  ```

  ```bash CLI
  ant messages create <<'YAML'
  model: claude-opus-5-5
  max_tokens: 1024
  messages:
    - role: user
      content: Help me plan a trip to Paris departing May 15, 2026
  # Saídas JSON: formato de resposta estruturado
  output_config:
    format:
      type: json_schema
      schema:
        type: object
        properties:
          summary:
            type: string
          next_steps:
            type: array
            items:
              type: string
        required: [summary, next_steps]
        additionalProperties: false
  # Uso de ferramentas estrito: parâmetros de ferramenta garantidos
  tools:
    - name: search_flights
      strict: true
      input_schema:
        type: object
        properties:
          destination:
            type: string
          date:
            type: string
            format: date
        required: [destination, date]
        additionalProperties: false
  YAML
  ```

  ```python Python
  response = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      messages=[
          {
              "role": "user",
              "content": "Help me plan a trip to Paris departing May 15, 2026",
          }
      ],
      # Saídas JSON: formato de resposta estruturado
      output_config={
          "format": {
              "type": "json_schema",
              "schema": {
                  "type": "object",
                  "properties": {
                      "summary": {"type": "string"},
                      "next_steps": {"type": "array", "items": {"type": "string"}},
                  },
                  "required": ["summary", "next_steps"],
                  "additionalProperties": False,
              },
          }
      },
      # Uso de ferramentas estrito: parâmetros de ferramenta garantidos
      tools=[
          {
              "name": "search_flights",
              "strict": True,
              "input_schema": {
                  "type": "object",
                  "properties": {
                      "destination": {"type": "string"},
                      "date": {"type": "string", "format": "date"},
                  },
                  "required": ["destination", "date"],
                  "additionalProperties": False,
              },
          }
      ],
  )

  print(response)
  ```

  ```typescript TypeScript
  const response = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Help me plan a trip to Paris departing May 15, 2026" }],
    // Saídas JSON: formato de resposta estruturado
    output_config: {
      format: {
        type: "json_schema",
        schema: {
          type: "object",
          properties: {
            summary: { type: "string" },
            next_steps: { type: "array", items: { type: "string" } }
          },
          required: ["summary", "next_steps"],
          additionalProperties: false
        }
      }
    },
    // Uso de ferramentas estrito: parâmetros de ferramenta garantidos
    tools: [
      {
        name: "search_flights",
        description: "Search for available flights to a destination on a specific date",
        strict: true,
        input_schema: {
          type: "object",
          properties: {
            destination: { type: "string" },
            date: { type: "string", format: "date" }
          },
          required: ["destination", "date"],
          additionalProperties: false
        }
      }
    ]
  });

  // Claude pode chamar a ferramenta primeiro (tool_use) ou responder com JSON (texto)
  console.log("Stop reason:", response.stop_reason);
  for (const block of response.content) {
    switch (block.type) {
      case "tool_use":
        console.log(`Tool call: ${block.name}(${JSON.stringify(block.input)})`);
        break;
      case "text":
        console.log("Response:", block.text);
        break;
    }
  }
  ```

  ```csharp C#
  var parameters = new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Messages = [new() { Role = Role.User, Content = "Help me plan a trip to Paris departing May 15, 2026" }],
      // Saídas JSON: formato de resposta estruturado
      OutputConfig = new OutputConfig
      {
          Format = new JsonOutputFormat
          {
              Schema = new Dictionary<string, JsonElement>
              {
                  ["type"] = JsonSerializer.SerializeToElement("object"),
                  ["properties"] = JsonSerializer.SerializeToElement(new
                  {
                      summary = new { type = "string" },
                      next_steps = new { type = "array", items = new { type = "string" } },
                  }),
                  ["required"] = JsonSerializer.SerializeToElement(new[] { "summary", "next_steps" }),
                  ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
              },
          },
      },
      // Uso de ferramentas estrito: parâmetros de ferramenta garantidos
      Tools =
      [
          new Tool
          {
              Name = "search_flights",
              Strict = true,
              InputSchema = new InputSchema(new Dictionary<string, JsonElement>
              {
                  ["properties"] = JsonSerializer.SerializeToElement(new Dictionary<string, object>
                  {
                      ["destination"] = new { type = "string" },
                      ["date"] = new { type = "string", format = "date" },
                  }),
                  ["required"] = JsonSerializer.SerializeToElement(new[] { "destination", "date" }),
                  ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
              }),
          }
      ],
  };

  var message = await client.Messages.Create(parameters);
  Console.WriteLine(message);
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Help me plan a trip to Paris departing May 15, 2026")),
  	},
  	// Saídas JSON: formato de resposta estruturado
  	OutputConfig: anthropic.OutputConfigParam{
  		Format: anthropic.JSONOutputFormatParam{
  			Schema: map[string]any{
  				"type":                 "object",
  				"additionalProperties": false,
  				"properties": map[string]any{
  					"summary":    map[string]any{"type": "string"},
  					"next_steps": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
  				},
  				"required": []string{"summary", "next_steps"},
  			},
  		},
  	},
  	// Uso de ferramentas estrito: parâmetros de ferramenta garantidos
  	Tools: []anthropic.ToolUnionParam{
  		{OfTool: &anthropic.ToolParam{
  			Name:   "search_flights",
  			Strict: anthropic.Bool(true),
  			InputSchema: anthropic.ToolInputSchemaParam{
  				Properties: map[string]any{
  					"destination": map[string]any{"type": "string"},
  					"date":        map[string]any{"type": "string", "format": "date"},
  				},
  				Required: []string{"destination", "date"},
  				ExtraFields: map[string]any{
  					"additionalProperties": false,
  				},
  			}}},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(response.Content)
  ```

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

  // Saídas JSON: formato de resposta estruturado
  JsonOutputFormat.Schema outputSchema = JsonOutputFormat.Schema.builder()
      .putAdditionalProperty("type", JsonValue.from("object"))
      .putAdditionalProperty("properties", JsonValue.from(Map.of(
          "summary", Map.of("type", "string"),
          "next_steps", Map.of("type", "array", "items", Map.of("type", "string"))
      )))
      .putAdditionalProperty("required", JsonValue.from(List.of("summary", "next_steps")))
      .putAdditionalProperty("additionalProperties", JsonValue.from(false))
      .build();

  // Uso de ferramentas estrito: parâmetros de ferramenta garantidos
  InputSchema toolSchema = InputSchema.builder()
      .properties(JsonValue.from(Map.of(
          "destination", Map.of("type", "string"),
          "date", Map.of("type", "string", "format", "date")
      )))
      .putAdditionalProperty("required", JsonValue.from(List.of("destination", "date")))
      .putAdditionalProperty("additionalProperties", JsonValue.from(false))
      .build();

  MessageCreateParams params = MessageCreateParams.builder()
      .model(Model.CLAUDE_OPUS_5_5)
      .maxTokens(1024L)
      .addUserMessage("Help me plan a trip to Paris departing May 15, 2026")
      .outputConfig(OutputConfig.builder()
          .format(JsonOutputFormat.builder().schema(outputSchema).build())
          .build())
      .addTool(Tool.builder()
          .name("search_flights")
          .description("Search for available flights to a destination on a specific date")
          .strict(true)
          .inputSchema(toolSchema)
          .build())
      .build();

  Message response = client.messages().create(params);
  IO.println(response);
  ```

  ```php PHP
  use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
  use Anthropic\Lib\Contracts\StructuredOutputModel;
  use Anthropic\Messages\ToolUseBlock;

  $client = new Client();

  class TripPlan implements StructuredOutputModel
  {
      use StructuredOutputModelTrait;

      public string $summary;
      public array $next_steps;
  }

  $message = $client->messages->create(
      maxTokens: 1024,
      messages: [
          ['role' => 'user', 'content' => 'Help me plan a trip to Paris departing May 15, 2026']
      ],
      model: 'claude-opus-5-5',
      // Saídas JSON: formato de resposta estruturado
      outputConfig: ['format' => TripPlan::class],
      // Uso de ferramentas estrito: parâmetros de ferramenta garantidos
      tools: [
          [
              'name' => 'search_flights',
              'strict' => true,
              'input_schema' => [
                  'type' => 'object',
                  'properties' => [
                      'destination' => ['type' => 'string'],
                      'date' => ['type' => 'string', 'format' => 'date']
                  ],
                  'required' => ['destination', 'date'],
                  'additionalProperties' => false
              ]
          ]
      ],
  );

  // Claude pode chamar a ferramenta primeiro (tool_use) ou responder com JSON (text)
  $plan = $message->parsedOutput();
  if ($plan instanceof TripPlan) {
      echo $plan->summary, "\n";
  } elseif ($toolUse = array_find($message->content, fn($block) => $block instanceof ToolUseBlock)) {
      echo "Tool call: {$toolUse->name}(", json_encode($toolUse->input), ")\n";
  }
  ```

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

  message = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [
      {role: "user", content: "Help me plan a trip to Paris departing May 15, 2026"}
    ],
    # Saídas JSON: formato de resposta estruturado
    output_config: {
      format: {
        type: :json_schema,
        schema: {
          type: "object",
          properties: {
            summary: {type: "string"},
            next_steps: {type: "array", items: {type: "string"}}
          },
          required: ["summary", "next_steps"],
          additionalProperties: false
        }
      }
    },
    # Uso de ferramentas estrito: parâmetros de ferramenta garantidos
    tools: [
      {
        name: "search_flights",
        strict: true,
        input_schema: {
          type: "object",
          properties: {
            destination: {type: "string"},
            date: {type: "string", format: "date"}
          },
          required: ["destination", "date"],
          additionalProperties: false
        }
      }
    ]
  )
  puts message
  ```
</CodeGroup>

## Considerações importantes

### Compilação e cache de gramática

As saídas estruturadas usam amostragem restrita com artefatos de gramática compilados. Isso introduz algumas características de desempenho que você deve conhecer:

* **Latência da primeira requisição:** Na primeira vez que você usa um schema específico, há latência adicional enquanto a gramática é compilada

* **Cache automático:** As gramáticas compiladas são armazenadas em cache por 24 horas a partir do último uso, tornando as requisições subsequentes muito mais rápidas

* **Invalidação do cache:** O cache é invalidado se você alterar:

  * A estrutura do schema JSON
  * O conjunto de ferramentas na sua requisição (ao usar saídas estruturadas e uso de ferramentas juntos)
  * Alterar apenas os campos `name` ou `description` não invalida o cache

### Modificação do prompt e custos de tokens

Ao usar saídas estruturadas, o Claude recebe automaticamente um "system prompt" (prompt do sistema) adicional explicando o formato de saída esperado. Isso significa que:

* Sua contagem de tokens de entrada é ligeiramente maior
* O prompt injetado custa tokens como qualquer outro prompt do sistema
* Alterar o parâmetro `output_config.format` invalidará qualquer [cache de prompt](https://platform.claude.com/docs/pt-BR/build-with-claude/prompt-caching) para aquela thread de conversa

### Limitações do JSON Schema

As saídas estruturadas suportam o JSON Schema padrão com algumas limitações. Tanto as saídas JSON quanto o uso estrito de ferramentas compartilham essas limitações.

<Accordion title="Recursos suportados">
  * Todos os tipos básicos: object, array, string, integer, number, boolean, null
  * `enum` (somente strings, números, booleanos ou nulls - sem tipos complexos). Para uma ressalva sobre capitalização, consulte [Saídas inválidas](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#invalid-outputs).
  * `const`
  * `anyOf` e `allOf` (com limitações - `allOf` com `$ref` não é suportado)
  * `$ref`, `$def` e `definitions` (`$ref` externo não é suportado)
  * Propriedade `default` para todos os tipos suportados
  * `required` e `additionalProperties` (deve ser definido como `false` para objetos)
  * Formatos de string: `date-time`, `time`, `date`, `duration`, `email`, `hostname`, `uri`, `ipv4`, `ipv6`, `uuid`
  * `minItems` de array (somente os valores 0 e 1 são suportados)
</Accordion>

<Accordion title="Não suportado">
  * Schemas recursivos
  * Tipos complexos dentro de enums
  * `$ref` externo (por exemplo, `'$ref': 'http://...'`)
  * Restrições numéricas (como `minimum`, `maximum`, `multipleOf`)
  * Restrições de string (`minLength`, `maxLength`)
  * Restrições de array além de `minItems` de 0 ou 1
  * `additionalProperties` definido como qualquer coisa diferente de `false`

  Se você usar um recurso não suportado, receberá um erro 400 com detalhes.
</Accordion>

<Accordion title="Suporte a padrões (regex)">
  **Recursos de regex suportados:**

  * Correspondência completa (`^...$`) e correspondência parcial
  * Quantificadores: `*`, `+`, `?`, casos simples de `{n,m}`
  * Classes de caracteres: `[]`, `.`, `\d`, `\w`, `\s`
  * Grupos: `(...)`

  **NÃO suportados:**

  * Referências retroativas a grupos (por exemplo, `\1`, `\2`)
  * Asserções lookahead/lookbehind (por exemplo, `(?=...)`, `(?!...)`)
  * Limites de palavra: `\b`, `\B`
  * Quantificadores `{n,m}` complexos com intervalos grandes

  Padrões regex simples funcionam bem. Padrões complexos podem resultar em erros 400.
</Accordion>

<Tip>
  Os helpers do SDK podem transformar schemas com [restrições não suportadas pela API](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#json-schema-limitations). Consulte [Como funciona a transformação do SDK](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#how-sdk-transformation-works).
</Tip>

### Ordenação de propriedades

Ao usar saídas estruturadas, as propriedades nos objetos mantêm a ordenação definida no seu schema, com uma ressalva importante: **as propriedades obrigatórias aparecem primeiro, seguidas pelas propriedades opcionais**.

Por exemplo, dado este schema:

```json
{
  "type": "object",
  "properties": {
    "notes": { "type": "string" },
    "name": { "type": "string" },
    "email": { "type": "string" },
    "age": { "type": "integer" }
  },
  "required": ["name", "email"],
  "additionalProperties": false
}
```

A saída ordenará as propriedades como:

1. `name` (obrigatória, na ordem do schema)
2. `email` (obrigatória, na ordem do schema)
3. `notes` (opcional, na ordem do schema)
4. `age` (opcional, na ordem do schema)

Isso significa que a saída pode ter esta aparência:

```json
{
  "name": "John Smith",
  "email": "john@example.com",
  "notes": "Interested in enterprise plan",
  "age": 35
}
```

Se a ordem das propriedades na saída for importante para sua aplicação, marque todas as propriedades como obrigatórias ou leve em conta essa reordenação na sua lógica de análise.

### Saídas inválidas

Embora as saídas estruturadas garantam a conformidade com o schema na maioria dos casos, há cenários em que a saída pode não corresponder ao seu schema:

**Recusas** (`stop_reason: "refusal"`)

O Claude mantém suas propriedades de segurança e utilidade mesmo ao usar saídas estruturadas. Se o Claude recusar uma requisição por motivos de segurança:

* A resposta tem `stop_reason: "refusal"`
* Você receberá um código de status 200
* Você será cobrado pelos tokens gerados
* A saída pode não corresponder ao seu schema porque a mensagem de recusa tem precedência sobre as restrições do schema

Uma propriedade que solicita o pensamento do modelo ou um raciocínio passo a passo pode levar a uma recusa `reasoning_extraction`. Em vez disso, peça uma explicação curta. Consulte [Mantenha o raciocínio nos blocos de pensamento](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback#keep-reasoning-in-thinking-blocks).

**Limite de tokens atingido** (`stop_reason: "max_tokens"`)

Se a resposta for cortada por atingir o limite de `max_tokens`:

* A resposta tem `stop_reason: "max_tokens"`
* A saída pode estar incompleta e não corresponder ao seu schema
* Tente novamente com um valor de `max_tokens` maior para obter a saída estruturada completa

**Capitalização de valores enum**

As saídas estruturadas não garantem a capitalização de valores `enum` e `const` de string: o Claude pode retornar um valor que difere do seu schema apenas na capitalização, normalmente na primeira letra de uma palavra após um espaço. Por exemplo, dado este schema:

```json
{
  "type": "string",
  "enum": ["Conversation Topic 1", "Conversation Topic 2", "Conversation topic 3"]
}
```

A saída pode conter `"Conversation Topic 3"` ("T" maiúsculo) mesmo que esse valor exato não esteja no enum. A resposta é concluída normalmente, sem erro e sem `stop_reason` especial. Isso se aplica tanto às saídas JSON quanto ao uso estrito de ferramentas. Compare valores enum sem diferenciar maiúsculas de minúsculas e evite valores enum que difiram apenas na capitalização.

### Limites de complexidade de schema

As saídas estruturadas funcionam compilando seus schemas JSON em uma gramática que restringe a saída do Claude. Schemas mais complexos produzem gramáticas maiores que levam mais tempo para compilar. Para proteger contra tempos de compilação excessivos, a API impõe vários limites de complexidade.

#### Limites explícitos

Os seguintes limites se aplicam a todas as requisições com `output_config.format` ou `strict: true`:

| Limite                              | Valor | Descrição                                                                                                                                                                                                        |
| ----------------------------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Ferramentas estritas por requisição | 20    | Número máximo de ferramentas com `strict: true`. Ferramentas não estritas não contam para esse limite.                                                                                                           |
| Parâmetros opcionais                | 24    | Total de parâmetros opcionais em todos os schemas de ferramentas estritas e schemas de saída JSON. Cada parâmetro não listado em `required` conta para esse limite.                                              |
| Parâmetros com tipos união          | 16    | Total de parâmetros que usam `anyOf` ou arrays de tipos (por exemplo, `"type": ["string", "null"]`) em todos os schemas estritos. Estes são especialmente custosos porque criam custo de compilação exponencial. |

<Note>
  Esses limites se aplicam ao total combinado de todos os schemas estritos em uma única requisição. Por exemplo, se você tiver 4 ferramentas estritas com 6 parâmetros opcionais cada, atingirá o limite de 24 parâmetros mesmo que nenhuma ferramenta individual pareça complexa.
</Note>

#### Limites internos adicionais

Além dos limites explícitos na tabela anterior, existem limites internos adicionais sobre o tamanho da gramática compilada. Esses limites existem porque a complexidade do schema não se reduz a uma única dimensão: recursos como parâmetros opcionais, tipos união, objetos aninhados e número de ferramentas interagem entre si de maneiras que podem tornar a gramática compilada desproporcionalmente grande.

Quando esses limites são excedidos, você receberá um erro 400 com a mensagem "Schema is too complex for compilation." Esses erros significam que a complexidade combinada dos seus schemas excede o que pode ser compilado de forma eficiente, mesmo que cada limite individual na tabela anterior seja satisfeito. Como medida final de contenção, a API também impõe um **tempo limite de compilação de 180 segundos**. Schemas que passam em todas as verificações explícitas, mas produzem gramáticas compiladas muito grandes, podem atingir esse tempo limite.

#### Dicas para reduzir a complexidade do schema

Se você estiver atingindo os limites de complexidade, experimente estas estratégias em ordem:

1. **Marque apenas as ferramentas críticas como estritas.** Se você tiver muitas ferramentas, reserve isso para ferramentas em que violações de schema causam problemas reais e confie na aderência natural do Claude para ferramentas mais simples.

2. **Reduza os parâmetros opcionais.** Torne os parâmetros `required` sempre que possível. Cada parâmetro opcional aproximadamente dobra uma parte do espaço de estados da gramática. Se um parâmetro sempre tem um padrão razoável, considere torná-lo obrigatório e fazer com que o Claude forneça esse padrão explicitamente.

3. **Simplifique estruturas aninhadas.** Objetos profundamente aninhados com campos opcionais aumentam a complexidade. Achate as estruturas sempre que possível.

4. **Divida em várias requisições.** Se você tiver muitas ferramentas estritas, considere dividi-las em requisições separadas ou subagentes.

Para problemas persistentes com schemas válidos, [entre em contato com o suporte](https://support.claude.com/en/articles/9015913-how-to-get-support) com a definição do seu schema.

## Migrando do beta

O parâmetro `output_format` foi movido para `output_config.format`, e os cabeçalhos beta não são mais necessários. O parâmetro `output_format` está descontinuado e será removido no futuro. Para usá-lo mesmo assim, adicione o cabeçalho beta `structured-outputs-2025-11-13`. Sem ele, a API retorna um erro 400.

O SDK Python (v1.0 e posteriores) não aceita `output_format={...}` em `client.beta.messages.create()` ou `count_tokens()` e gera um `TypeError`. Use `output_config` em vez disso. Consulte [Usando um schema JSON bruto](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#using-a-raw-json-schema) para o formato atualizado da API.

## Retenção de dados

Os prompts e as respostas são processados com ZDR ao usar saídas estruturadas. No entanto, o schema JSON em si é temporariamente armazenado em cache por até 24 horas desde o último uso para fins de otimização. Nenhum dado de prompt ou resposta é retido além da resposta da API.

As saídas estruturadas são elegíveis para HIPAA, mas **PHI não deve ser incluída nas definições de schema JSON**. A API compila schemas JSON em gramáticas que são armazenadas em cache separadamente do conteúdo das mensagens, e esses schemas em cache não recebem as mesmas proteções de PHI que os prompts e as respostas. Não inclua PHI em nomes de propriedades do schema, valores `enum`, valores `const` ou expressões regulares `pattern`. PHI deve aparecer apenas no conteúdo das mensagens (prompts e respostas), onde é protegida pelas salvaguardas da HIPAA.

Para elegibilidade de ZDR e HIPAA em todos os recursos, consulte [API e retenção de dados](https://platform.claude.com/docs/pt-BR/manage-claude/api-and-data-retention).

## Compatibilidade de recursos

**Funciona com:**

* **[Processamento em lote](https://platform.claude.com/docs/pt-BR/build-with-claude/batch-processing):** Processe saídas estruturadas em escala com 50% de desconto
* **[Contagem de tokens](https://platform.claude.com/docs/pt-BR/build-with-claude/token-counting):** Conte tokens sem compilação
* **[Streaming](https://platform.claude.com/docs/pt-BR/build-with-claude/streaming):** Faça streaming de saídas estruturadas como respostas normais
* **[Uso combinado](https://platform.claude.com/docs/pt-BR/build-with-claude/structured-outputs#using-both-features-together):** Use saídas JSON (`output_config.format`) e uso estrito de ferramentas (`strict: true`) juntos na mesma requisição

**Incompatível com:**

* **[Citações](https://platform.claude.com/docs/pt-BR/build-with-claude/citations):** As citações exigem intercalar blocos de citação com texto, o que conflita com as restrições estritas de schema JSON. Retorna erro 400 se as citações estiverem habilitadas com `output_config.format`.
* **Preenchimento prévio de mensagens:** Incompatível com saídas JSON

<Tip>
  **Escopo da gramática:** As gramáticas se aplicam apenas à saída direta do Claude, não a chamadas de uso de ferramentas, resultados de ferramentas ou tags de pensamento (ao usar [pensamento](https://platform.claude.com/docs/pt-BR/build-with-claude/thinking)). O estado da gramática é redefinido entre as seções, permitindo que o Claude pense livremente enquanto ainda produz saída estruturada na resposta final.
</Tip>

## Próximos passos

<CardGroup cols={2}>
  <Card title="Citações" icon="book-bookmark" href="https://platform.claude.com/docs/pt-BR/build-with-claude/citations">
    Faça o Claude citar suas fontes ao responder perguntas sobre documentos fornecidos.
  </Card>

  <Card title="Uso estrito de ferramentas" icon="check" href="https://platform.claude.com/docs/pt-BR/agents-and-tools/tool-use/strict-tool-use">
    Imponha a conformidade com JSON Schema nas entradas de ferramentas do Claude com amostragem restrita por gramática.
  </Card>

  <Card title="Uso de ferramentas com o Claude" icon="wrench" href="https://platform.claude.com/docs/pt-BR/agents-and-tools/tool-use/overview">
    Conecte o Claude a ferramentas e APIs externas. Saiba onde as ferramentas são executadas e como funciona o loop agêntico.
  </Card>

  <Card title="Preços" icon="calculator" href="https://platform.claude.com/docs/pt-BR/about-claude/pricing">
    Saiba mais sobre a estrutura de preços da Anthropic para modelos e recursos.
  </Card>
</CardGroup>
