openapi: 3.1.0
info:
  title: API de Anúncios
  description: Busca de categorias, atributos, publicação e gestão de anúncios, e ofertas em anúncios de catálogo (buybox).
  version: 1.0.0
  contact:
    name: UniSupri
servers:
  - url: https://api.sandbox.samdevel.com.br
    description: Sandbox (ambiente de homologação)
tags:
  - name: Categorias
    description: |-
      Busca e navegação de categorias para publicação de anúncios.
      
      A categoria define quais atributos são obrigatórios ou opcionais no anúncio. Use a busca para encontrar a categoria mais específica para seu produto.
  - name: Publicacao
    description: |-
      Criação e publicação de anúncios no marketplace.
      
      Inclui simulação (validação prévia), criação do rascunho **com descrição e ficha técnica em um único payload**, vinculação de SKUs às variações do catálogo, checklist de revisão e ativação para venda.
      
      **Fluxo resumido:**
      
      1. `POST /api/items/simulate`: valida sem persistir.
      2. `POST /api/items/create`: cria como `draft` (já com `description` e `technical_sheets` se desejar).
      3. `GET /api/items/{id}/review-checklist`: verifica o que ainda falta.
      4. `PUT /api/items/{id}/publish`: envia para revisão (`pending_review`).
      
      > Para o fluxo passo a passo completo, consulte o **Guia de Anúncios**.
  - name: Gestão de Anúncios
    description: |-
      Consulta e edição dos anúncios já criados.
      
      Listagem paginada com filtros e ordenação, detalhe completo, descrição (com preview do conteúdo processado), score de qualidade com dicas, atributos, variações e fichas técnicas.
      
      As rotas de edição valem para anúncios do tipo `default`. Anúncios de catálogo são mantidos pela plataforma — para eles o vendedor gerencia apenas as próprias ofertas (veja **Catálogo e Ofertas**).
  - name: Catálogo e Ofertas
    description: |-
      Descoberta de anúncios de catálogo e gestão das suas ofertas.
      
      No catálogo, vários vendedores competem dentro do mesmo anúncio: você encontra o anúncio, escolhe a opção (variação) desejada e vincula um SKU seu. Isso cria uma **oferta**, que passa a disputar a buybox com as ofertas dos demais vendedores.
      
      Aqui também estão a listagem das suas ofertas, a atualização de status (ativar/pausar) e a remoção do vínculo.
paths:
  "/api/categories/departaments":
    get:
      tags:
        - Categorias
      summary: Listar Departamentos
      description: Retorna os departamentos ativos da plataforma, ordenados por nome. Use para filtrar a busca de categorias.
      security:
        - bearer: []
      responses:
        "200":
          description: Lista de departamentos
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  - id: 1
                    name: Alimentos e Bebidas
                    icon_svg: null
                  - id: 2
                    name: Tecnologia
                    icon_svg: <svg>...</svg>
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/categories/browse":
    get:
      tags:
        - Categorias
      summary: Navegar Categorias
      description: Navegacao hierarquica de categorias. Sem parametros retorna as categorias raiz. Use `parent_id` para descer na arvore. Quando `has_children` for `false`, a categoria é folha e pode receber anúncios.
      parameters:
        - name: departament_id
          in: query
          description: Filtrar por departamento
          required: false
          schema:
            type: integer
        - name: parent_id
          in: query
          description: ID da categoria pai (omitir para raiz)
          required: false
          schema:
            type: integer
      security:
        - bearer: []
      responses:
        "200":
          description: Lista de categorias no nivel solicitado
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  - id: 93
                    name: Computadores e Notebooks
                    has_children: true
                    departament:
                      id: 2
                      name: Tecnologia
                    parent: null
                  - id: 95
                    name: Celulares e Smartphones
                    has_children: false
                    departament:
                      id: 2
                      name: Tecnologia
                    parent: null
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/categories/search":
    get:
      tags:
        - Categorias
      summary: Buscar Categorias
      description: Busca categorias por nome. Retorna apenas categorias de último nível (folhas da árvore), que são as únicas que podem ser usadas para criar anúncios.
      parameters:
        - name: search
          in: query
          description: Termo de busca (obrigatorio)
          required: true
          schema:
            type: string
            example: notebook
        - name: departament_id
          in: query
          description: Filtrar por departamento
          required: false
          schema:
            type: integer
            example: 2
      security:
        - bearer: []
      responses:
        "200":
          description: Lista de categorias encontradas
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/CategoriesResponse"
              example:
                success: true
                message_code: SUCCESS
                data:
                  - id: 94
                    name: Notebooks
                    description: Laptops e portateis
                    departament:
                      id: 2
                      name: Tecnologia
                      icon_svg: null
                    parent:
                      id: 93
                      parent_id: null
                      name: Computadores e Notebooks
                      hierarchy:
                        - id: 93
                          name: Computadores e Notebooks
                    is_visible: true
                    priority: 1
                    domain: computers
                    level: 1
                    hierarchy:
                      - id: 93
                        name: Computadores e Notebooks
                      - id: 94
                        name: Notebooks
                    settings: []
                    catalog_overrides: null
                    total_children: 0
                    children: []
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/categories/{category_id}/attributes":
    get:
      tags:
        - Publicacao
      summary: Atributos da Categoria
      description: |-
        Retorna os atributos disponíveis para a categoria. Inclui características (marca, material) e variações (cor, tamanho).
        
        Use `only_features=1` ou `only_variations=1` para filtrar — os dois juntos não são aceitos (retorna 422).
        
        Com `matrix=true`, os atributos vêm agrupados por seção (`data` é uma lista de grupos `{ key, label, items }`). Sem `matrix` (ou `matrix=false`), `data` é a lista plana de atributos.
      parameters:
        - name: category_id
          in: path
          required: true
          description: ID da categoria selecionada
          schema:
            type: integer
        - name: only_variations
          in: query
          required: false
          description: Retornar apenas atributos de variações
          schema:
            type: string
        - name: only_features
          in: query
          required: false
          description: Retornar apenas características do produto
          schema:
            type: string
            example: "1"
        - name: matrix
          in: query
          required: false
          description: "Quando `true`, agrupa os atributos por matriz de organização (Identificação, Aparência, Técnico, ...). Default: `false` (lista plana)."
          schema:
            type: boolean
            example: true
      security:
        - bearer: []
      responses:
        "200":
          description: Lista de atributos da categoria
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/CategoryAttributesResponse"
              example:
                success: true
                message_code: SUCCESS
                data:
                  - key: appearance
                    label: Aparência e Design
                    items:
                      - id: 210
                        attribute_id: 3
                        category_id: 121
                        is_required: false
                        is_feature: false
                        is_variant: true
                        is_combinable: true
                        is_filter: true
                        attribute_data:
                          id: 3
                          name: Cor
                          type: color
                          value_type: select
                          is_feature: false
                          is_variant: true
                          is_calculable: false
                          domain: global
                          ui:
                            public_name: Cor
                            description: Cor predominante do produto
                            matrix: appearance
                            select_type: select
                          value_definition:
                            fields:
                              value:
                                type: string
                                required: true
                                label: Nome da cor
                                placeholder: "Ex.: Vermelho Ferrari"
                              main_color:
                                type: string
                                required: true
                                label: Cor principal
                                placeholder: "Ex.: Vermelho"
                              hex:
                                type: string
                                required: true
                                pattern: ^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$
                                label: Código HEX
                                placeholder: "Ex.: #FF0000"
                            options:
                              - id: 15
                                attribute_id: 3
                                value: Verde
                                component:
                                  value: Verde
                                  main_color: Verde
                                  hex: "#2E7D32"
                                  brightness: dark
                                position: 1
                                is_default: false
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/categories/{category_id}/combine-attributes":
    post:
      tags:
        - Publicacao
      summary: Gerar Combinações de Variações
      description: |-
        Gera todas as combinações possíveis a partir dos atributos de variação selecionados. Exemplo: Voltagem (110V, 220V) + Cor (Azul, Verde) = 4 combinações.
        
        Apenas atributos marcados como `is_combinable` na categoria podem ser usados. Cada valor pode ser um texto, o `id` de uma opção pré-cadastrada ou um objeto — por exemplo `{ "value": "Vinho", "hex": "#722F37", "custom": true }` para cor customizada, ou `{ "width": 50, "height": 70, "unit": "cm" }` para dimensões.
      parameters:
        - name: category_id
          in: path
          required: true
          description: ID da categoria selecionada
          schema:
            type: integer
      security:
        - bearer: []
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              required:
                - attributes
              properties:
                attributes:
                  type: object
                  additionalProperties:
                    type: array
                    items:
                      type:
                        - string
                        - integer
                        - object
                  description: Mapa de attribute_id -> array de valores. Cada valor pode ser texto, option_id ou objeto (cor customizada, valor com unidade, dimensões)
                primary_attribute_id:
                  type: integer
                  nullable: true
                  description: "ID do atributo principal (opcional, usado para organizar fotos por variação; default: primeiro atributo informado)"
            example:
              attributes:
                "1":
                  - 110 V
                  - 220 V
                "3":
                  - Azul
                  - Verde
              primary_attribute_id: 1
      responses:
        "200":
          description: Combinacoes geradas com sucesso
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/AttributeCombinationsResponse"
              example:
                success: true
                message_code: SUCCESS
                data:
                  combinations:
                    - attributes:
                        - attribute_id: 1
                          attribute_name: Voltagem
                          value: 110 V
                        - attribute_id: 3
                          attribute_name: Cor
                          value: Azul
                          hex: "#1565C0"
                          main_color: Azul
                          brightness: dark
                      attributes_details:
                        Voltagem: 110 V
                        Cor: Azul
                      description: "Voltagem: 110 V, Cor: Azul"
                    - attributes:
                        - attribute_id: 1
                          attribute_name: Voltagem
                          value: 110 V
                        - attribute_id: 3
                          attribute_name: Cor
                          value: Verde
                          hex: "#2E7D32"
                          main_color: Verde
                          brightness: dark
                      attributes_details:
                        Voltagem: 110 V
                        Cor: Verde
                      description: "Voltagem: 110 V, Cor: Verde"
                    - attributes:
                        - attribute_id: 1
                          attribute_name: Voltagem
                          value: 220 V
                        - attribute_id: 3
                          attribute_name: Cor
                          value: Azul
                          hex: "#1565C0"
                          main_color: Azul
                          brightness: dark
                      attributes_details:
                        Voltagem: 220 V
                        Cor: Azul
                      description: "Voltagem: 220 V, Cor: Azul"
                    - attributes:
                        - attribute_id: 1
                          attribute_name: Voltagem
                          value: 220 V
                        - attribute_id: 3
                          attribute_name: Cor
                          value: Verde
                          hex: "#2E7D32"
                          main_color: Verde
                          brightness: dark
                      attributes_details:
                        Voltagem: 220 V
                        Cor: Verde
                      description: "Voltagem: 220 V, Cor: Verde"
                  primary_attribute:
                    id: 1
                    name: Voltagem
                    has_options: true
                    default_unit: null
                    values:
                      - value: 110 V
                        label: 110 V
                      - value: 220 V
                        label: 220 V
        "400":
          description: Pedido inválido (sem atributos, atributo não combinável, valor não permitido ou categoria inexistente)
          content:
            "application/json":
              example:
                success: false
                message_code: BAD_REQUEST
                message: Atributo ID 5 não é combinável ou não pertence à categoria
                data: Atributo ID 5 não é combinável ou não pertence à categoria
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/items/simulate":
    post:
      tags:
        - Publicacao
      summary: Simular Anúncio
      description: |-
        Valida os dados do anúncio sem persistir. O body é idêntico ao de `POST /api/items/create` e aceita todos os campos do mesmo schema `CreateAdvertisementRequest`, incluindo `description` e `technical_sheets`.
        
        **Validações executadas:**
        - Atributos obrigatórios da categoria preenchidos
        - GTIN (EAN) válido, quando informado
        - Estrutura e tipos dos campos (incluindo `description.layout`, `description.raw_content` e cada item de `technical_sheets`)
        - `seller_sku` (ou `variations[].seller_sku`) existente na loja, com preço e estoque ativos
        - Imagens referenciadas existem na plataforma
        
        Use antes de criar para identificar erros de payload com antecedência. Se retornar **200**, os dados estão prontos para chamar `POST /api/items/create`.
        
        Na resposta, `item_id` é apenas ilustrativo (sequencial zero) — o ID real só é gerado na criação. Erros de regra de negócio (ex.: SKU sem estoque ativo) retornam **422** com `data.reason` e `data.details`.
      security:
        - bearer: []
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              "$ref": "#/components/schemas/CreateAdvertisementRequest"
            example:
              title: Caixa de Som JBL Go!
              category_id: 121
              gtin:
                type: 13
                value: "6925281995583"
              attributes:
                - id: 1
                  value_id: 3
                  value: HyperX
                - id: 397
                  value: 12
                  unit: ml
              variations:
                - seller_sku: FK-JBL-2000-AZUL
                  attributes:
                    - attribute_id: 397
                      attribute_name: Quantidade
                      value: "1"
                      unit: ml
                  images:
                    - id: "{{image_id}}"
              images:
                - id: "{{image_id}}"
              description:
                layout: markdown
                raw_content: |-
                  ## Caixa de Som JBL Go!
                  
                  Som potente, bateria de longa duração e resistência à água.
              technical_sheets:
                - type: technical_specification
                  title: Especificações Técnicas
                  items:
                    - item_key: Potência
                      item_value: 4,2W RMS
                      display_order: 0
                    - item_key: Bateria
                      item_value: 5 horas
                      display_order: 1
      responses:
        "200":
          description: Anuncio validado com sucesso (objeto projetado, nada foi persistido)
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/SimulatedAdvertisementResponse"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/create":
    post:
      tags:
        - Publicacao
      summary: Criar Anúncio
      description: |-
        Cria o anúncio com status `draft` (rascunho).
        
        É obrigatório informar **`seller_sku`** (anúncio sem variações) **ou** **`variations`** (cada uma com seu `seller_sku`). Os SKUs precisam existir previamente na loja, com preço e estoque configurados.
        
        O payload aceita opcionalmente os campos **`description`** (texto longo do anúncio) e **`technical_sheets`** (fichas técnicas). Assim o integrador pode criar o anúncio já completo, sem precisar chamar `PUT /api/items/{id}/description` e `POST /api/items/{id}/technical-sheets` em separado.
        
        Se estes campos forem omitidos, eles podem ser preenchidos depois usando os endpoints específicos. Após o rascunho estar pronto, ative o anúncio com [PUT /api/items/{publication_id}/publish](/reference#tag/publicacao/PUT/api/items/{publication_id}/publish).
      security:
        - bearer: []
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              "$ref": "#/components/schemas/CreateAdvertisementRequest"
            example:
              title: Caixa de Som JBL Go!
              category_id: 121
              gtin:
                type: 13
                value: "6925281995583"
              attributes:
                - id: 1
                  value_id: 3
                  value: HyperX
                - id: 397
                  value: 12
                  unit: ml
              variations:
                - seller_sku: FK-JBL-2000-AZUL
                  attributes:
                    - attribute_id: 397
                      attribute_name: Quantidade
                      value: "1"
                      unit: ml
                  images:
                    - id: "{{image_id}}"
              images:
                - id: "{{image_id}}"
              description:
                layout: markdown
                raw_content: |-
                  ## Caixa de Som JBL Go!
                  
                  Som potente, bateria de longa duração e resistência à água.
              technical_sheets:
                - type: technical_specification
                  title: Especificações Técnicas
                  items:
                    - item_key: Potência
                      item_value: 4,2W RMS
                      display_order: 0
                    - item_key: Bateria
                      item_value: 5 horas
                      display_order: 1
      responses:
        "201":
          description: Anuncio criado com sucesso como rascunho
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/CreatedAdvertisementResponse"
              example:
                success: true
                message_code: RESOURCE_CREATED
                data:
                  item_id: SAM-0000000000007
                  title: Caixa de Som JBL Go!
                  short_description: null
                  slug: caixa-de-som-jbl-go
                  type:
                    value: default
                    label: Padrão
                  status:
                    value: draft
                    label: Rascunho
                  seller_sku: null
                  price_range: null
                  score: null
                  campaigns: []
                  pricing_context: []
                  frontend_sync_status: pending
                  last_frontend_sync_at: null
                  submitted_for_review_at: null
                  reviewed_at: null
                  rejection_reason: null
                  gtin:
                    type: "13"
                    value: "6925281995583"
                  store:
                    store_id: 01K8PB0KMM36AY2P0NKSZBP2NA
                    store_name: Minha Loja
                    store_code: MINHALOJA
                    store_status: active
                    store_url: minha-loja
                    store_type: store_seller
                    commission_table_id: 1
                    max_locations: 1
                    features: []
                    company: {}
                    shares_products: false
                    shares_stock_locations: false
                    shares_logistics: false
                    is_primary: false
                    primary_store: null
                  department:
                    id: 2
                    name: Tecnologia
                    icon_svg: null
                  category:
                    id: 121
                    parent_id: 94
                    name: Caixas de Som
                    hierarchy:
                      - id: 94
                        name: Notebooks
                      - id: 121
                        name: Caixas de Som
                  thumbnail: null
                  images:
                    - id: 9c2f6a1e-4b7d-4f3a-9e2b-1d5c8a7f6e3b
                      resources:
                        - name: sm
                          url: https://cdn.exemplo.com.br/images/9c2f6a1e-sm.webp
                        - name: lg
                          url: https://cdn.exemplo.com.br/images/9c2f6a1e-lg.webp
                  attributes:
                    - attribute_id: 1
                      attribute_name: Marca
                      attribute_value: HyperX
                      value_unit: null
                      value_id: 3
                      component: null
                  variations:
                    - offer_id: 01K8QC1NPP47BZ3Q1PLTACQ3OB
                      description: "Quantidade: 1 ml"
                      attributes:
                        - attribute_id: 397
                          attribute_name: Quantidade
                          value: "1"
                          unit: ml
                      status: pending
                      type: offer
                      images: []
                      seller_sku: FK-JBL-2000-AZUL
                      offer:
                        price_type: default
                        price_from: 299.9
                        prices: []
                        quantity: 50
                        price: 299.9
                        original_price: null
                        has_discount: false
                        discount_percent: 0
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/{publication_id}/review-checklist":
    get:
      tags:
        - Publicacao
      summary: Checklist de Revisão
      description: |-
        Retorna o estado do anúncio em rascunho com a lista de verificações necessárias para publicação (imagem, título, descrições, atributos obrigatórios da categoria e SKU vinculado). Use para descobrir o que ainda falta antes de chamar `PUT /publish`.
        
        O retorno traz `checks` (cada verificação com `ok`) e `issues` (pendências, com `severity`). Itens com `severity=error` bloqueiam a publicação; `warning` (ex.: descrição curta) é apenas recomendação. O campo `ready=true` indica que o anúncio passa nos requisitos e pode ser publicado.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` retornado em `POST /api/items/create`"
          schema:
            type: string
            example: SAM-0000000000007
      responses:
        "200":
          description: Checklist obtido
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  ready: false
                  issues:
                    - code: missing_short_description
                      severity: warning
                      message: Recomendamos preencher a descrição curta para melhor exibição em listagens.
                      field: short_description
                    - code: missing_required_attribute
                      severity: error
                      message: "Atributo obrigatório não preenchido: Marca"
                      field: attributes
                  checks:
                    - code: image
                      label: Pelo menos uma imagem
                      ok: true
                    - code: title
                      label: Título preenchido
                      ok: true
                    - code: short_description
                      label: Descrição curta preenchida
                      ok: false
                    - code: description
                      label: Descrição detalhada preenchida
                      ok: true
                    - code: required_attributes
                      label: Atributos obrigatórios da categoria
                      ok: false
                    - code: sku
                      label: SKU vinculado
                      ok: true
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/items/{publication_id}/publish":
    put:
      tags:
        - Publicacao
      summary: Publicar Anúncio
      description: |-
        Envia o anúncio em rascunho (`draft`) para revisão da plataforma. O status muda para `pending_review` e o anúncio fica disponível para venda assim que aprovado.
        
        **Pré-requisitos:**
        
        - O anúncio precisa estar em `draft` e ser do tipo padrão (`default`).
        - Precisa passar no checklist. Consulte [GET /review-checklist](/reference#tag/publicacao/GET/api/items/{publication_id}/review-checklist) antes para evitar 422.
        
        Se o checklist falhar, a resposta vem com código 422 e o campo `checklist` (no topo do envelope) traz as verificações e pendências.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` retornado em `POST /api/items/create`"
          schema:
            type: string
            example: SAM-0000000000007
      responses:
        "200":
          description: Anúncio enviado para revisão
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/CreatedAdvertisementResponse"
              example:
                success: true
                message_code: SUCCESS
                data:
                  item_id: SAM-0000000000007
                  title: Caixa de Som JBL Go!
                  short_description: Som potente e portátil
                  slug: caixa-de-som-jbl-go
                  type:
                    value: default
                    label: Padrão
                  status:
                    value: pending_review
                    label: Revisão
                  seller_sku: null
                  price_range: null
                  score: null
                  campaigns: []
                  pricing_context: []
                  frontend_sync_status: pending
                  last_frontend_sync_at: null
                  submitted_for_review_at: "2026-06-10 14:32:11"
                  reviewed_at: null
                  rejection_reason: null
                  gtin:
                    type: "13"
                    value: "6925281995583"
                  department:
                    id: 2
                    name: Tecnologia
                    icon_svg: null
                  category:
                    id: 121
                    parent_id: 94
                    name: Caixas de Som
                    hierarchy: []
                  thumbnail: null
                  images: []
                  attributes: []
                  variations: []
        "400":
          description: Anúncio não está em rascunho ou tipo não suportado
          content:
            "application/json":
              example:
                success: false
                message_code: BAD_REQUEST
                data:
                  - Apenas anúncios em rascunho podem ser publicados.
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          description: Checklist de revisão não passou
          content:
            "application/json":
              example:
                success: false
                message_code: BAD_REQUEST
                data:
                  - O anúncio ainda não está pronto para revisão.
                checklist:
                  ready: false
                  issues:
                    - code: missing_required_attribute
                      severity: error
                      message: "Atributo obrigatório não preenchido: Marca"
                      field: attributes
                  checks:
                    - code: required_attributes
                      label: Atributos obrigatórios da categoria
                      ok: false
  "/api/items/catalog/options/{optionId}/attach-sku":
    post:
      tags:
        - Catálogo e Ofertas
      summary: Vincular SKU à Variação
      description: |-
        Vincula um produto (SKU) a uma variação de um anúncio de **catálogo** ativo, criando uma oferta da loja. O SKU deve existir na loja e ter preço e estoque configurados. Pode-se usar SKUs diferentes por variação ou o mesmo para todas.
        
        Após o vínculo, o recálculo da buybox é agendado em background — por isso `is_buybox_winner` pode vir `false` logo após a criação.
      parameters:
        - name: optionId
          in: path
          required: true
          description: ID da opção/variação do catálogo (26 caracteres)
          schema:
            type: string
      security:
        - bearer: []
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              "$ref": "#/components/schemas/AttachSKURequest"
            example:
              seller_sku: FK-JBL-2000-VERDE
              status: active
      responses:
        "200":
          description: SKU vinculado com sucesso
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/AttachedSKUResponse"
              example:
                success: true
                message_code: SUCCESS
                data:
                  offer_id: 01K8QC1NPP47BZ3Q1PLTACQ3OB
                  seller_sku: FK-JBL-2000-VERDE
                  status: active
                  is_buybox_winner: false
                  last_buybox_calculation: null
                  price_data:
                    price: 299.9
                  stock_data:
                    id: 12345
                    product_id: 01K8PB0KMM36AY2P0NKSZBP2NB
                    location_id: 01K8PB0KMM36AY2P0NKSZBP2NC
                    quantity: 50
                    reserved_quantity: 5
                    available_quantity: 45
                  publication:
                    item_id: SAM-0000000000003
                    title: Caixa de Som JBL Go!
                    status: active
                    type: catalog
                    thumbnail_id: 9c2f6a1e-4b7d-4f3a-9e2b-1d5c8a7f6e3b
                  option:
                    uid: 01K8QC0XYZ47BZ3Q1PLTACQ3OA
                    description: "Voltagem: 110 V, Cor: Verde"
                    attributes:
                      - attribute_id: 1
                        attribute_name: Voltagem
                        value: 110 V
                        unit: null
                        value_id: 1
                      - attribute_id: 3
                        attribute_name: Cor
                        value: Verde
                        unit: null
                        value_id: 15
                    type: option
                    status: active
                    images: []
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "409":
          "$ref": "#/components/responses/Duplicated"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items":
    get:
      tags:
        - Gestão de Anúncios
      summary: Listar Anúncios
      description: |-
        Lista paginada dos anúncios da loja autenticada, com busca, filtros e ordenação.
        
        A paginação vem aninhada em **`data.meta.pagination`** (padrão `PaginatedResource`), com os itens em `data.data`.
        
        Quando `search` é informado, a ordenação passa a ser por relevância e o parâmetro `sort` é ignorado.
      security:
        - bearer: []
      parameters:
        - name: search
          in: query
          required: false
          description: Busca textual (título, identificadores etc.). Também aceito como `filter[search]`.
          schema:
            type: string
            example: furadeira
        - name: sort
          in: query
          required: false
          description: "Campo de ordenação. Prefixe com `-` para ordem decrescente. Aceita: `item_id`, `title`, `status`, `type`, `created_at`, `updated_at`, `score`, `price`. Default: `-updated_at`. Ignorado quando há `search`."
          schema:
            type: string
            example: "-updated_at"
        - name: filter[item_id]
          in: query
          required: false
          description: Filtra por `item_id` exato.
          schema:
            type: string
            example: SAM-0000000000007
        - name: filter[type]
          in: query
          required: false
          description: Tipo do anúncio.
          schema:
            type: string
            enum:
              - default
              - catalog
        - name: filter[status]
          in: query
          required: false
          description: Status do anúncio.
          schema:
            type: string
            enum:
              - active
              - draft
              - pending_review
              - inactive
              - paused
        - name: filter[category_id]
          in: query
          required: false
          description: ID da categoria. Inclui automaticamente as subcategorias descendentes.
          schema:
            type: integer
            example: 152
        - name: filter[departament_id]
          in: query
          required: false
          description: ID do departamento.
          schema:
            type: integer
            example: 3
        - name: filter[score_tier]
          in: query
          required: false
          description: "Faixa de score: `low` (<40), `medium` (40–69) ou `high` (≥70). Anúncios sem score contam como `low`."
          schema:
            type: string
            enum:
              - low
              - medium
              - high
        - name: filter[price_min]
          in: query
          required: false
          description: Preço mínimo.
          schema:
            type: number
            example: 50
        - name: filter[price_max]
          in: query
          required: false
          description: Preço máximo.
          schema:
            type: number
            example: 300
        - name: filter[widget]
          in: query
          required: false
          description: "Recortes prontos de dashboard. Para anúncios `default`: `campanha` (em campanha ativa), `inativos`, `sem_estoque`. Combinado com `filter[type]=catalog`: `vencendo` (ofertas que vencem a buybox), `competindo` (variações com mais de uma oferta ativa), `sem_estoque`."
          schema:
            type: string
            example: sem_estoque
        - name: per_page
          in: query
          required: false
          description: Itens por página. Default `15`, máximo `100`.
          schema:
            type: integer
            default: 15
            example: 15
        - name: page
          in: query
          required: false
          schema:
            type: integer
            example: 1
      responses:
        "200":
          description: Anúncios listados
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  meta:
                    search_query: ""
                    filters: []
                    pagination:
                      page: 1
                      per_page: 15
                      last_page: 1
                      has_prev_page: false
                      has_next_page: false
                      records:
                        from: 1
                        to: 2
                        records: 2
                  data:
                    - id: 42
                      item_id: SAM-0000000000007
                      title: Furadeira de Impacto 650W 110V
                      type: default
                      status: active
                      thumbnail:
                        id: 01JD2R8KQX5VTWMA3B7YCE9FGH
                        resource:
                          name: thumbnail
                          url: https://cdn.exemplo.com/images/furadeira-thumb.webp
                      department:
                        id: 3
                        name: Ferramentas
                      category:
                        id: 152
                        name: Furadeiras
                      price_range:
                        - 189.9
                        - 219.9
                      store:
                        id: 12
                        store_name: Loja das Ferramentas
                      score:
                        total: 78
                        tier: high
                      frontend_sync_status: synced
                      last_frontend_sync_at: "2026-06-09 14:32:11"
                    - id: 57
                      item_id: SAM-0000000000012
                      title: Parafusadeira sem Fio 12V com Maleta
                      type: default
                      status: paused
                      thumbnail: null
                      department:
                        id: 3
                        name: Ferramentas
                      category:
                        id: 158
                        name: Parafusadeiras
                      price_range: null
                      store:
                        id: 12
                        store_name: Loja das Ferramentas
                      score:
                        total: 35
                        tier: low
                      frontend_sync_status: pending
                      last_frontend_sync_at: null
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/items/my-categories-tree":
    get:
      tags:
        - Gestão de Anúncios
      summary: Árvore de Categorias da Loja
      description: |-
        Retorna a árvore departamento → categoria → subcategoria considerando apenas onde a loja autenticada tem pelo menos um anúncio. Útil para montar filtros de navegação no portal.
        
        Cada categoria traz `count` (anúncios diretamente nela) e `total_count` (incluindo as descendentes).
      security:
        - bearer: []
      parameters:
        - name: type
          in: query
          required: false
          description: Restringe a contagem a um tipo de anúncio.
          schema:
            type: string
            enum:
              - default
              - catalog
      responses:
        "200":
          description: Árvore montada
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  departaments:
                    - id: 3
                      name: Ferramentas
                      count: 8
                      categories:
                        - id: 150
                          name: Ferramentas Elétricas
                          parent_id: null
                          count: 2
                          total_count: 8
                          children:
                            - id: 152
                              name: Furadeiras
                              parent_id: 150
                              count: 5
                              total_count: 5
                              children: []
                            - id: 158
                              name: Parafusadeiras
                              parent_id: 150
                              count: 1
                              total_count: 1
                              children: []
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/items/{publication_id}":
    get:
      tags:
        - Gestão de Anúncios
      summary: Detalhe do Anúncio
      description: "Retorna o anúncio completo: dados gerais, imagens, atributos, variações com preço/estoque, score, campanhas e estado de sincronização com a vitrine. É o mesmo shape devolvido por `POST /api/items/create`."
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      responses:
        "200":
          description: Anúncio encontrado
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/CreatedAdvertisementResponse"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
    put:
      tags:
        - Gestão de Anúncios
      summary: Atualizar Dados Gerais
      description: |-
        Atualiza título, descrição curta, miniatura e galeria de imagens de um anúncio do tipo `default`. Anúncios de catálogo não podem ser editados pelo vendedor (retorna `403`).
        
        As imagens devem ter sido enviadas previamente pela API de mídia — aqui você só referencia os IDs. Campos omitidos permanecem como estão (exceto `title`, que é sempre obrigatório).
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                title:
                  type: string
                  maxLength: 100
                  description: Título do anúncio
                short_description:
                  type:
                    - string
                    - "null"
                  maxLength: 260
                  description: Descrição curta exibida em listagens
                thumbnail_id:
                  type:
                    - string
                    - "null"
                  description: ID de uma imagem já enviada, usada como miniatura
                images:
                  type:
                    - array
                    - "null"
                  description: Galeria de imagens do anúncio (substitui a atual quando enviada)
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                        description: ID da imagem
                    required:
                      - id
              required:
                - title
            example:
              title: Furadeira de Impacto 650W 110V com Maleta
              short_description: Furadeira de impacto 650W com mandril de 1/2" e maleta para transporte.
              thumbnail_id: 01JD2R8KQX5VTWMA3B7YCE9FGH
              images:
                - id: 01JD2R8KQX5VTWMA3B7YCE9FGH
                - id: 01JD2R8KQX5VTWMA3B7YCE9FGJ
      responses:
        "200":
          description: "Anúncio atualizado (envelope com `message_code: RESOURCE_UPDATED` e o anúncio completo em `data`)"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/CreatedAdvertisementResponse"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/{publication_id}/description":
    get:
      tags:
        - Gestão de Anúncios
      summary: Consultar Descrição
      description: Retorna a descrição detalhada do anúncio no formato bruto (`raw_content`), junto com o `layout` em que foi gravada. Para ver o conteúdo já processado para exibição, use `GET .../description/preview`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      responses:
        "200":
          description: Descrição encontrada
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  layout: markdown
                  raw_content: |-
                    ## Furadeira de Impacto 650W
                    
                    Ideal para alvenaria, madeira e metal.
                    
                    - Mandril de 1/2"
                    - Empunhadura auxiliar
                    - Maleta inclusa
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
    put:
      tags:
        - Gestão de Anúncios
      summary: Atualizar Descrição
      description: |-
        Substitui a descrição detalhada de um anúncio do tipo `default`. Envie o conteúdo bruto e o `layout` correspondente — o processamento para exibição acontece na leitura.
        
        Anúncios de catálogo têm descrição mantida pela plataforma e retornam `403`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                layout:
                  type: string
                  enum:
                    - text
                    - html
                    - markdown
                  description: Formato do `raw_content`
                raw_content:
                  type: string
                  description: Conteúdo bruto da descrição
              required:
                - layout
                - raw_content
            example:
              layout: markdown
              raw_content: |-
                ## Furadeira de Impacto 650W
                
                Ideal para alvenaria, madeira e metal.
      responses:
        "200":
          description: Descrição atualizada
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  layout: markdown
                  raw_content: |-
                    ## Furadeira de Impacto 650W
                    
                    Ideal para alvenaria, madeira e metal.
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/{publication_id}/description/preview":
    get:
      tags:
        - Gestão de Anúncios
      summary: Pré-visualizar Descrição
      description: "Retorna a descrição com o conteúdo já processado de acordo com o `layout` (ex.: Markdown convertido para HTML), em `processed_content`. Use para mostrar ao vendedor exatamente o que o comprador verá."
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      responses:
        "200":
          description: Preview gerado
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  layout: markdown
                  raw_content: |-
                    ## Furadeira de Impacto 650W
                    
                    Ideal para alvenaria, madeira e metal.
                  processed_content: |-
                    <h2>Furadeira de Impacto 650W</h2>
                    <p>Ideal para alvenaria, madeira e metal.</p>
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/items/{publication_id}/score":
    get:
      tags:
        - Gestão de Anúncios
      summary: Score do Anúncio
      description: |-
        Retorna o score de qualidade do anúncio (0–100) com o detalhamento por pilar: **qualidade** (fotos, título, descrição — até 70 pts), **reputação** (avaliações e perguntas respondidas — até 30 pts) e **vendas** (até 30 pts).
        
        Cada item do `breakdown` traz os pontos obtidos, o máximo possível, um `status` (`excellent`, `info`, `warning`) e uma dica (`tip`) de como melhorar.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      responses:
        "200":
          description: Score calculado
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  total_score: 78
                  last_calculated_at: "2026-06-09T14:30:00-03:00"
                  breakdown:
                    quality:
                      score: 50
                      max: 70
                      details:
                        - item: fotos
                          points: 20
                          max: 20
                          status: excellent
                          tip: Você tem o número ideal de fotos.
                        - item: titulo
                          points: 15
                          max: 15
                          status: excellent
                          tip: Seu título está com tamanho ideal.
                        - item: descricao
                          points: 5
                          max: 15
                          status: warning
                          tip: Escreva uma descrição mais completa (mais de 500 caracteres).
                    reputation:
                      score: 26
                      max: 30
                      details:
                        - item: stars
                          points: 16
                          max: 20
                          status: excellent
                          tip: Sua média é 4.2 estrelas.
                        - item: questions
                          points: 10
                          max: 10
                          status: excellent
                          tip: Todas as perguntas foram respondidas.
                    sales:
                      score: 2
                      max: 30
                      details:
                        - item: orders
                          points: 2
                          max: 30
                          status: info
                          tip: Item com 3 vendas confirmadas.
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/items/{publication_id}/attributes":
    put:
      tags:
        - Gestão de Anúncios
      summary: Atualizar Atributos
      description: |-
        Substitui os atributos base de um anúncio do tipo `default`. Os atributos enviados são validados contra a categoria atual do anúncio — obrigatórios da categoria precisam estar presentes e valores de atributos com opções pré-definidas precisam existir.
        
        Atributos de dimensão exigem `width`/`height` (e `depth` em 3D) com `unit`; atributos do tipo lista exigem `items`. As variações existentes não são alteradas.
        
        Anúncios de catálogo retornam `403`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                attributes:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    properties:
                      id:
                        type: integer
                        description: ID do atributo (aceita também o alias `attribute_id`)
                      value:
                        description: Valor do atributo. Para atributos com opções pré-definidas, informe `value` ou `value_id`. Aceita o alias `attribute_value`.
                      value_id:
                        type:
                          - integer
                          - "null"
                        description: ID da opção pré-definida do atributo
                      unit:
                        type:
                          - string
                          - "null"
                        description: Unidade de medida (obrigatória em atributos numéricos com unidade). Aceita o alias `value_unit`.
                      width:
                        type:
                          - number
                          - "null"
                        description: Largura — atributos de dimensão (2D/3D)
                      height:
                        type:
                          - number
                          - "null"
                        description: Altura — atributos de dimensão (2D/3D)
                      depth:
                        type:
                          - number
                          - "null"
                        description: Profundidade — atributos de dimensão 3D
                      items:
                        type:
                          - array
                          - "null"
                        description: Itens — atributos do tipo lista
                        items:
                          type: object
                    required:
                      - id
              required:
                - attributes
            example:
              attributes:
                - id: 2
                  value_id: 25
                - id: 14
                  value: "650"
                  unit: W
                - id: 21
                  width: 28
                  height: 9
                  depth: 26
                  unit: cm
      responses:
        "200":
          description: "Atributos atualizados (envelope com `message_code: RESOURCE_UPDATED` e o anúncio completo em `data`)"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/CreatedAdvertisementResponse"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/{publication_id}/variations":
    get:
      tags:
        - Gestão de Anúncios
      summary: Listar Variações
      description: Lista as variações do anúncio com atributos, imagens e a oferta de cada uma (preço, estoque, desconto). Em anúncios `default` o identificador vem como `offer_id`; em catálogo, como `option_id`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      responses:
        "200":
          description: Variações listadas
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/PublicationVariationOut"
              example:
                success: true
                message_code: SUCCESS
                data:
                  - offer_id: 01JD4A0B1C2D3E4F5G6H7J8K9M
                    description: "Voltagem: 110 V"
                    attributes:
                      - attribute_id: 7
                        attribute_name: Voltagem
                        value: 110 V
                        value_id: 71
                    status: active
                    type: offer
                    images:
                      - id: 01JD2R8KQX5VTWMA3B7YCE9FGH
                        resources:
                          - name: sm
                            url: https://cdn.exemplo.com/images/furadeira-sm.webp
                          - name: lg
                            url: https://cdn.exemplo.com/images/furadeira-lg.webp
                    seller_sku: FUR-650-110
                    offer:
                      price_type: default
                      price_from: 219.9
                      prices: []
                      quantity: 35
                      price: 189.9
                      original_price: 219.9
                      has_discount: true
                      discount_percent: 14
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
    post:
      tags:
        - Gestão de Anúncios
      summary: Adicionar Variação
      description: |-
        Adiciona uma variação a um anúncio do tipo `default`, vinculando um SKU da loja. O `seller_sku` precisa pertencer à loja autenticada (ou estar associado a ela, no modo de produtos compartilhados) — preço e estoque da variação derivam dele.
        
        Os atributos da variação seguem as mesmas regras de validação dos atributos do anúncio (opções pré-definidas, unidades, dimensões e listas).
        
        Anúncios de catálogo retornam `403`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                description:
                  type: string
                  description: "Descrição legível da combinação (ex.: Voltagem: 220 V)"
                seller_sku:
                  type: string
                  description: SKU da loja vinculado à variação
                images:
                  type:
                    - array
                    - "null"
                  description: Imagens específicas da variação
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                        description: ID da imagem
                    required:
                      - id
                status:
                  type:
                    - string
                    - "null"
                  enum:
                    - pending
                    - active
                    - hidden
                  description: Status inicial da variação
                attributes:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    properties:
                      attribute_id:
                        type: integer
                        description: ID do atributo
                      attribute_name:
                        type:
                          - string
                          - "null"
                      value:
                        description: Valor do atributo. Para atributos com opções pré-definidas, informe `value` ou `value_id`.
                      value_id:
                        type:
                          - integer
                          - "null"
                        description: ID da opção pré-definida do atributo
                      unit:
                        type:
                          - string
                          - "null"
                        description: Unidade de medida (obrigatória em atributos numéricos com unidade)
                      width:
                        type:
                          - number
                          - "null"
                        description: Largura — atributos de dimensão (2D/3D)
                      height:
                        type:
                          - number
                          - "null"
                        description: Altura — atributos de dimensão (2D/3D)
                      depth:
                        type:
                          - number
                          - "null"
                        description: Profundidade — atributos de dimensão 3D
                      items:
                        type:
                          - array
                          - "null"
                        description: Itens — atributos do tipo lista
                        items:
                          type: object
                    required:
                      - attribute_id
              required:
                - description
                - seller_sku
                - attributes
            example:
              description: "Voltagem: 220 V"
              seller_sku: FUR-650-220
              status: active
              images:
                - id: 01JD2R8KQX5VTWMA3B7YCE9FGJ
              attributes:
                - attribute_id: 7
                  attribute_name: Voltagem
                  value: 220 V
                  value_id: 72
      responses:
        "201":
          description: "Variação criada (envelope com `message_code: RESOURCE_CREATED` e a variação em `data`)"
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    "$ref": "#/components/schemas/PublicationVariationOut"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
    put:
      tags:
        - Gestão de Anúncios
      summary: Atualizar Variações em Lote
      description: |-
        Substitui o conjunto de variações de um anúncio do tipo `default`. Envie a lista completa — variações ausentes deixam de existir.
        
        Em anúncios `default` cada variação precisa de `seller_sku` (a ausência retorna `422`). No `status`, `paused` é aceito como sinônimo de `hidden`.
        
        Anúncios de catálogo retornam `403`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                variations:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    properties:
                      seller_sku:
                        type:
                          - string
                          - "null"
                        description: SKU da loja (obrigatório em anúncios `default`)
                      description:
                        type:
                          - string
                          - "null"
                        description: Descrição legível da combinação
                      images:
                        type:
                          - array
                          - "null"
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                      status:
                        type:
                          - string
                          - "null"
                        enum:
                          - pending
                          - active
                          - hidden
                          - paused
                        description: "`paused` é normalizado para `hidden`"
                      attributes:
                        type:
                          - array
                          - "null"
                        items:
                          type: object
                          properties:
                            attribute_id:
                              type: integer
                              description: ID do atributo
                            attribute_name:
                              type:
                                - string
                                - "null"
                            value:
                              description: Valor do atributo. Para atributos com opções pré-definidas, informe `value` ou `value_id`.
                            value_id:
                              type:
                                - integer
                                - "null"
                              description: ID da opção pré-definida do atributo
                            unit:
                              type:
                                - string
                                - "null"
                              description: Unidade de medida (obrigatória em atributos numéricos com unidade)
                            width:
                              type:
                                - number
                                - "null"
                              description: Largura — atributos de dimensão (2D/3D)
                            height:
                              type:
                                - number
                                - "null"
                              description: Altura — atributos de dimensão (2D/3D)
                            depth:
                              type:
                                - number
                                - "null"
                              description: Profundidade — atributos de dimensão 3D
                            items:
                              type:
                                - array
                                - "null"
                              description: Itens — atributos do tipo lista
                              items:
                                type: object
                          required:
                            - attribute_id
              required:
                - variations
            example:
              variations:
                - seller_sku: FUR-650-110
                  description: "Voltagem: 110 V"
                  status: active
                  attributes:
                    - attribute_id: 7
                      attribute_name: Voltagem
                      value: 110 V
                      value_id: 71
                - seller_sku: FUR-650-220
                  description: "Voltagem: 220 V"
                  status: hidden
                  attributes:
                    - attribute_id: 7
                      attribute_name: Voltagem
                      value: 220 V
                      value_id: 72
      responses:
        "200":
          description: "Variações atualizadas (envelope com `message_code: RESOURCE_UPDATED` e o anúncio completo em `data`)"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/CreatedAdvertisementResponse"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/{publication_id}/variations/{uid}":
    put:
      tags:
        - Gestão de Anúncios
      summary: Atualizar Variação
      description: |-
        Atualiza uma variação específica de um anúncio do tipo `default`. Todos os campos são opcionais — o que não for enviado é mantido.
        
        Anúncios de catálogo retornam `403`; variação inexistente retorna `404`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
        - name: uid
          in: path
          required: true
          description: ID da variação (campo `offer_id`/`option_id`, 26 caracteres)
          schema:
            type: string
            example: 01JD4A0B1C2D3E4F5G6H7J8K9M
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                description:
                  type:
                    - string
                    - "null"
                seller_sku:
                  type:
                    - string
                    - "null"
                  description: Novo SKU da loja para a variação
                images:
                  type:
                    - array
                    - "null"
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                    required:
                      - id
                status:
                  type:
                    - string
                    - "null"
                  enum:
                    - pending
                    - active
                    - hidden
                attributes:
                  type:
                    - array
                    - "null"
                  items:
                    type: object
                    properties:
                      attribute_id:
                        type: integer
                        description: ID do atributo
                      attribute_name:
                        type:
                          - string
                          - "null"
                      value:
                        description: Valor do atributo. Para atributos com opções pré-definidas, informe `value` ou `value_id`.
                      value_id:
                        type:
                          - integer
                          - "null"
                        description: ID da opção pré-definida do atributo
                      unit:
                        type:
                          - string
                          - "null"
                        description: Unidade de medida (obrigatória em atributos numéricos com unidade)
                      width:
                        type:
                          - number
                          - "null"
                        description: Largura — atributos de dimensão (2D/3D)
                      height:
                        type:
                          - number
                          - "null"
                        description: Altura — atributos de dimensão (2D/3D)
                      depth:
                        type:
                          - number
                          - "null"
                        description: Profundidade — atributos de dimensão 3D
                      items:
                        type:
                          - array
                          - "null"
                        description: Itens — atributos do tipo lista
                        items:
                          type: object
                    required:
                      - attribute_id
            example:
              status: hidden
      responses:
        "200":
          description: "Variação atualizada (envelope com `message_code: RESOURCE_UPDATED` e a variação em `data`)"
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    "$ref": "#/components/schemas/PublicationVariationOut"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
    delete:
      tags:
        - Gestão de Anúncios
      summary: Remover Variação
      description: |-
        Remove uma variação do anúncio. Retorna `204` sem corpo — no cliente, cheque o status da resposta antes de tentar fazer parse de JSON.
        
        Anúncios de catálogo retornam `403`; variação inexistente retorna `404`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
        - name: uid
          in: path
          required: true
          description: ID da variação (campo `offer_id`/`option_id`, 26 caracteres)
          schema:
            type: string
            example: 01JD4A0B1C2D3E4F5G6H7J8K9M
      responses:
        "204":
          description: Variação removida (sem corpo)
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/items/{publication_id}/technical-sheets":
    get:
      tags:
        - Gestão de Anúncios
      summary: Listar Fichas Técnicas
      description: Lista as fichas técnicas do anúncio, opcionalmente filtrando por tipo. Anúncio inexistente ou que não pertence à loja retorna `404`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
        - name: type
          in: query
          required: false
          description: Filtra por tipo de ficha.
          schema:
            type: string
            enum:
              - technical_specification
              - characteristics
              - materials
              - installation
              - maintenance
              - safety
              - environmental
              - custom
      responses:
        "200":
          description: Fichas listadas
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/TechnicalSheet"
              example:
                success: true
                message_code: SUCCESS
                data:
                  - sheet_id: 01JD3F8GZQK2V5W7XA9BC4DE6H
                    publication_id: SAM-0000000000007
                    type:
                      value: technical_specification
                      label: Ficha Técnica
                      description: Especificações técnicas detalhadas do produto
                    title: Especificações gerais
                    items:
                      - item_id: 01JD3F8H1T8MN2P4Q6R8S0T2V4
                        item_key: Potência
                        item_value: 650 W
                        display_order: 0
                      - item_id: 01JD3F8H1T8MN2P4Q6R8S0T2W5
                        item_key: Voltagem
                        item_value: 110 V
                        display_order: 1
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
    post:
      tags:
        - Gestão de Anúncios
      summary: Criar Ficha Técnica
      description: |-
        Cria uma ficha técnica para o anúncio. A combinação de `type` + `title` é única por anúncio — repetir retorna `422`.
        
        Os `items` são opcionais na criação; você pode incluí-los depois via atualização ou importação de HTML.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                type:
                  type: string
                  enum:
                    - technical_specification
                    - characteristics
                    - materials
                    - installation
                    - maintenance
                    - safety
                    - environmental
                    - custom
                  description: Tipo da ficha técnica
                title:
                  type: string
                  maxLength: 255
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item_key:
                        type: string
                        maxLength: 255
                      item_value:
                        type: string
                        maxLength: 1000
                      display_order:
                        type: integer
                        minimum: 0
                    required:
                      - item_key
                      - item_value
              required:
                - type
                - title
            example:
              type: technical_specification
              title: Especificações gerais
              items:
                - item_key: Potência
                  item_value: 650 W
                  display_order: 0
                - item_key: Voltagem
                  item_value: 110 V
                  display_order: 1
      responses:
        "201":
          description: "Ficha criada (envelope com `message_code: RESOURCE_CREATED`)"
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    "$ref": "#/components/schemas/TechnicalSheet"
              example:
                success: true
                message_code: RESOURCE_CREATED
                data:
                  sheet_id: 01JD3F8GZQK2V5W7XA9BC4DE6H
                  publication_id: SAM-0000000000007
                  type:
                    value: technical_specification
                    label: Ficha Técnica
                    description: Especificações técnicas detalhadas do produto
                  title: Especificações gerais
                  items:
                    - item_id: 01JD3F8H1T8MN2P4Q6R8S0T2V4
                      item_key: Potência
                      item_value: 650 W
                      display_order: 0
                    - item_id: 01JD3F8H1T8MN2P4Q6R8S0T2W5
                      item_key: Voltagem
                      item_value: 110 V
                      display_order: 1
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/{publication_id}/technical-sheets/{ulid}":
    get:
      tags:
        - Gestão de Anúncios
      summary: Consultar Ficha Técnica
      description: Retorna uma ficha técnica específica com todos os itens. Ficha inexistente ou de anúncio que não pertence à loja retorna `404`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
        - name: ulid
          in: path
          required: true
          description: ID da ficha técnica (campo `sheet_id`, 26 caracteres)
          schema:
            type: string
            example: 01JD3F8GZQK2V5W7XA9BC4DE6H
      responses:
        "200":
          description: Ficha encontrada
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    "$ref": "#/components/schemas/TechnicalSheet"
              example:
                success: true
                message_code: SUCCESS
                data:
                  sheet_id: 01JD3F8GZQK2V5W7XA9BC4DE6H
                  publication_id: SAM-0000000000007
                  type:
                    value: technical_specification
                    label: Ficha Técnica
                    description: Especificações técnicas detalhadas do produto
                  title: Especificações gerais
                  items:
                    - item_id: 01JD3F8H1T8MN2P4Q6R8S0T2V4
                      item_key: Potência
                      item_value: 650 W
                      display_order: 0
                    - item_id: 01JD3F8H1T8MN2P4Q6R8S0T2W5
                      item_key: Voltagem
                      item_value: 110 V
                      display_order: 1
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
    put:
      tags:
        - Gestão de Anúncios
      summary: Atualizar Ficha Técnica
      description: |-
        Atualiza tipo, título e/ou itens de uma ficha técnica. Todos os campos são opcionais. Ao enviar `items`, a lista substitui a atual por completo.
        
        Se a mudança de `type`/`title` colidir com outra ficha do mesmo anúncio, retorna `422`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
        - name: ulid
          in: path
          required: true
          description: ID da ficha técnica (campo `sheet_id`, 26 caracteres)
          schema:
            type: string
            example: 01JD3F8GZQK2V5W7XA9BC4DE6H
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                type:
                  type: string
                  enum:
                    - technical_specification
                    - characteristics
                    - materials
                    - installation
                    - maintenance
                    - safety
                    - environmental
                    - custom
                title:
                  type: string
                  maxLength: 255
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item_key:
                        type: string
                        maxLength: 255
                      item_value:
                        type: string
                        maxLength: 1000
                      display_order:
                        type: integer
                        minimum: 0
                    required:
                      - item_key
                      - item_value
            example:
              title: Especificações técnicas
              items:
                - item_key: Potência
                  item_value: 650 W
                  display_order: 0
                - item_key: Rotação
                  item_value: 0–2.800 rpm
                  display_order: 1
      responses:
        "200":
          description: Ficha atualizada
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    "$ref": "#/components/schemas/TechnicalSheet"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
    delete:
      tags:
        - Gestão de Anúncios
      summary: Excluir Ficha Técnica
      description: Exclui uma ficha técnica e seus itens. Retorna `204` sem corpo — no cliente, cheque o status antes de tentar fazer parse de JSON.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
        - name: ulid
          in: path
          required: true
          description: ID da ficha técnica (campo `sheet_id`, 26 caracteres)
          schema:
            type: string
            example: 01JD3F8GZQK2V5W7XA9BC4DE6H
      responses:
        "204":
          description: Ficha excluída (sem corpo)
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/items/{publication_id}/technical-sheets/import":
    post:
      tags:
        - Gestão de Anúncios
      summary: Importar Ficha Técnica de HTML
      description: |-
        Cria uma ficha técnica nova extraindo os pares chave/valor de um trecho de HTML (ex.: tabela de especificações copiada do site do fabricante). Útil para não digitar item por item.
        
        A combinação `type` + `title` segue única por anúncio (`422` se repetir).
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                type:
                  type: string
                  enum:
                    - technical_specification
                    - characteristics
                    - materials
                    - installation
                    - maintenance
                    - safety
                    - environmental
                    - custom
                title:
                  type: string
                  maxLength: 255
                html_content:
                  type: string
                  description: "HTML de onde os itens serão extraídos (ex.: `<table>` de especificações)"
              required:
                - type
                - title
                - html_content
            example:
              type: technical_specification
              title: Especificações do fabricante
              html_content: <table><tr><td>Potência</td><td>650 W</td></tr><tr><td>Voltagem</td><td>110 V</td></tr></table>
      responses:
        "201":
          description: "Ficha criada a partir do HTML (envelope com `message_code: RESOURCE_CREATED`)"
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    "$ref": "#/components/schemas/TechnicalSheet"
              example:
                success: true
                message_code: RESOURCE_CREATED
                data:
                  sheet_id: 01JD3F8GZQK2V5W7XA9BC4DE6H
                  publication_id: SAM-0000000000007
                  type:
                    value: technical_specification
                    label: Ficha Técnica
                    description: Especificações técnicas detalhadas do produto
                  title: Especificações gerais
                  items:
                    - item_id: 01JD3F8H1T8MN2P4Q6R8S0T2V4
                      item_key: Potência
                      item_value: 650 W
                      display_order: 0
                    - item_id: 01JD3F8H1T8MN2P4Q6R8S0T2W5
                      item_key: Voltagem
                      item_value: 110 V
                      display_order: 1
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/{publication_id}/technical-sheets/{ulid}/import":
    post:
      tags:
        - Gestão de Anúncios
      summary: Importar Itens para Ficha Existente
      description: |-
        Extrai itens de um trecho de HTML e os **acrescenta** a uma ficha técnica existente. Chaves repetidas são ignoradas (a primeira ocorrência vence) e a ordem de exibição é renumerada ao final.
        
        Se nenhum item puder ser extraído do HTML, retorna `422`. Ficha que não pertence ao anúncio informado retorna `404`.
      security:
        - bearer: []
      parameters:
        - name: publication_id
          in: path
          required: true
          description: "`item_id` do anúncio"
          schema:
            type: string
            example: SAM-0000000000007
        - name: ulid
          in: path
          required: true
          description: ID da ficha técnica (campo `sheet_id`, 26 caracteres)
          schema:
            type: string
            example: 01JD3F8GZQK2V5W7XA9BC4DE6H
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                html_content:
                  type: string
                  description: HTML de onde os itens serão extraídos
              required:
                - html_content
            example:
              html_content: <table><tr><td>Rotação</td><td>0–2.800 rpm</td></tr></table>
      responses:
        "200":
          description: Itens importados e mesclados
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    "$ref": "#/components/schemas/TechnicalSheet"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/sku/{sku}":
    get:
      tags:
        - Gestão de Anúncios
      summary: Anúncios por SKU
      description: |-
        Lista todos os anúncios da loja que usam um SKU específico — seja no corpo do anúncio, nas variações ou nas suas ofertas de catálogo. Um mesmo SKU pode aparecer em anúncios `default` e `catalog` ao mesmo tempo.
        
        Útil antes de alterar ou desativar um SKU, para saber o que será impactado. SKU sem anúncios retorna lista vazia.
      security:
        - bearer: []
      parameters:
        - name: sku
          in: path
          required: true
          description: SKU da loja
          schema:
            type: string
            example: FUR-650-110
      responses:
        "200":
          description: Anúncios encontrados
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  - id: 01JD1PVBQ2K4M6N8P0R2T4V6X8
                    item_id: SAM-0000000000007
                    title: Furadeira de Impacto 650W 110V
                    short_description: Furadeira de impacto 650W com mandril de 1/2" e maleta.
                    type: default
                    status: active
                    slug: furadeira-de-impacto-650w-110v
                    store:
                      store_id: 01JD0STQ2K4M6N8P0R2T4V6X8Y
                      store_name: Loja das Ferramentas
                      store_code: LDF
                    department:
                      id: 3
                      name: Ferramentas
                    category:
                      id: 152
                      name: Furadeiras
                    thumbnail:
                      id: 01JD2R8KQX5VTWMA3B7YCE9FGH
                      resource:
                        name: thumbnail
                        url: https://cdn.exemplo.com/images/furadeira-thumb.webp
                    price_range:
                      - 189.9
                      - 219.9
                    score: 78
                    campaigns: []
                    frontend_sync_status: synced
                    last_frontend_sync_at: "2026-06-09 14:32:11"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/items/catalog/publications":
    get:
      tags:
        - Catálogo e Ofertas
      summary: Explorar Anúncios de Catálogo
      description: |-
        Lista paginada dos anúncios de catálogo ativos, disponíveis para a loja vincular SKUs. Cada anúncio vem com suas opções (variações) e indica, por opção, se a sua loja já tem oferta (`has_offer`) e quantas (`offer_count`).
        
        Use `has_relation` para ver só os anúncios onde você já oferta (`yes`) ou onde ainda não oferta (`no`). A paginação vem aninhada em `data.meta.pagination`.
      security:
        - bearer: []
      parameters:
        - name: search
          in: query
          required: false
          description: Busca textual no título do anúncio.
          schema:
            type: string
            example: caneta
        - name: has_relation
          in: query
          required: false
          description: "`yes`: apenas anúncios onde a loja já tem oferta; `no`: apenas onde ainda não tem. Omitido: todos."
          schema:
            type: string
            enum:
              - "yes"
              - "no"
        - name: per_page
          in: query
          required: false
          description: Itens por página. Default `15`.
          schema:
            type: integer
            default: 15
            example: 15
        - name: page
          in: query
          required: false
          schema:
            type: integer
            example: 1
      responses:
        "200":
          description: Anúncios de catálogo listados
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  meta:
                    search_query: ""
                    filters: []
                    pagination:
                      page: 1
                      per_page: 15
                      last_page: 1
                      has_prev_page: false
                      has_next_page: false
                      records:
                        from: 1
                        to: 1
                        records: 1
                  data:
                    - item_id: SAM-0000000000021
                      title: Caneta Esferográfica Azul 1.0mm
                      status: active
                      type: catalog
                      thumbnail_id: 01JD2R8KQX5VTWMA3B7YCE9FGH
                      thumbnail:
                        url: https://cdn.exemplo.com/images/caneta-sm.webp
                      department:
                        id: 5
                        name: Papelaria
                      category:
                        id: 233
                        name: Canetas
                      has_relation: true
                      total_offers: 1
                      has_variations: true
                      options_count: 2
                      options:
                        - option_id: 01JD4A0B1C2D3E4F5G6H7J8K9N
                          description: "Quantidade: 50 un"
                          attributes:
                            - attribute_id: 19
                              attribute_name: Quantidade
                              value: "50"
                              unit: un
                          has_offer: true
                          offer_count: 1
                        - option_id: 01JD4A0B1C2D3E4F5G6H7J8K9P
                          description: "Quantidade: 100 un"
                          attributes:
                            - attribute_id: 19
                              attribute_name: Quantidade
                              value: "100"
                              unit: un
                          has_offer: false
                          offer_count: 0
                      frontend_sync_status: synced
                      last_frontend_sync_at: "2026-06-09 10:21:44"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/catalog/{itemId}/options":
    get:
      tags:
        - Catálogo e Ofertas
      summary: Opções de um Anúncio de Catálogo
      description: |-
        Lista as variações (opções) de um anúncio de catálogo ativo, com atributos, imagens e os dados da oferta vencedora da buybox em `offer`. O `option_id` retornado é o que você usa em `POST /api/items/catalog/options/{optionId}/attach-sku` para vincular o seu SKU.
        
        Anúncio inexistente ou não ativo retorna `404`.
      security:
        - bearer: []
      parameters:
        - name: itemId
          in: path
          required: true
          description: "`item_id` do anúncio de catálogo"
          schema:
            type: string
            example: SAM-0000000000021
      responses:
        "200":
          description: Opções listadas
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/PublicationVariationOut"
              example:
                success: true
                message_code: SUCCESS
                data:
                  - option_id: 01JD4A0B1C2D3E4F5G6H7J8K9N
                    description: "Quantidade: 50 un"
                    attributes:
                      - attribute_id: 19
                        attribute_name: Quantidade
                        value: "50"
                        unit: un
                    status: active
                    type: option
                    images: []
                    offer:
                      price_type: default
                      price_from: 1245
                      prices: []
                      quantity: 2
                      price: 1245
                      original_price: null
                      has_discount: false
                      discount_percent: 0
                      buybox:
                        winner_store:
                          store_name: Papelaria Central
                          store_code: PPC
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/items/catalog/offers/{offerId}":
    put:
      tags:
        - Catálogo e Ofertas
      summary: Atualizar Oferta
      description: |-
        Atualiza o status de uma oferta sua vinculada a uma opção de catálogo. A atualização é restrita ao `status` — preço e estoque seguem o SKU vinculado.
        
        Após a mudança, a buybox da variação é recalculada automaticamente. Oferta inexistente ou de outra loja retorna `404`.
      security:
        - bearer: []
      parameters:
        - name: offerId
          in: path
          required: true
          description: ID da oferta (campo `offer_id`, 26 caracteres)
          schema:
            type: string
            example: 01JD5B2C3D4E5F6G7H8J9K0M1N
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                status:
                  type: string
                  enum:
                    - active
                    - paused
                    - inactive
                  description: Novo status da oferta
              required:
                - status
            example:
              status: paused
      responses:
        "200":
          description: Oferta atualizada
          content:
            "application/json":
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message_code:
                    type: string
                  data:
                    "$ref": "#/components/schemas/AttachedSKUData"
              example:
                success: true
                message_code: SUCCESS
                data:
                  offer_id: 01JD5B2C3D4E5F6G7H8J9K0M1N
                  seller_sku: CAN-AZ-50
                  status: paused
                  is_buybox_winner: false
                  last_buybox_calculation: "2026-06-09T13:05:22-03:00"
                  price_data:
                    price: 24.9
                  stock_data:
                    quantity: 120
                    available_quantity: 118
                  publication:
                    item_id: SAM-0000000000021
                    title: Caneta Esferográfica Azul 1.0mm
                    status: active
                    type: catalog
                    thumbnail_id: 01JD2R8KQX5VTWMA3B7YCE9FGH
                  option:
                    uid: 01JD4A0B1C2D3E4F5G6H7J8K9N
                    description: "Quantidade: 50 un"
                    attributes:
                      - attribute_id: 19
                        attribute_name: Quantidade
                        value: "50"
                        unit: un
                    type: option
                    status: active
                    images: []
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
    delete:
      tags:
        - Catálogo e Ofertas
      summary: Remover Oferta
      description: |-
        Remove o vínculo do seu SKU com a opção de catálogo (exclui a oferta) e dispara o recálculo da buybox da variação.
        
        **Atenção:** diferente das demais rotas DELETE da API, esta retorna `200` com uma mensagem em `data` — não `204`. Oferta inexistente ou de outra loja retorna `422`.
      security:
        - bearer: []
      parameters:
        - name: offerId
          in: path
          required: true
          description: ID da oferta (campo `offer_id`, 26 caracteres)
          schema:
            type: string
            example: 01JD5B2C3D4E5F6G7H8J9K0M1N
      responses:
        "200":
          description: Oferta removida
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  message: Oferta removida com sucesso
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/items/catalog/my-offers":
    get:
      tags:
        - Catálogo e Ofertas
      summary: Minhas Ofertas
      description: |-
        Lista paginada dos anúncios de catálogo onde a sua loja tem ofertas, agrupando por anúncio → opção → ofertas (`buybox_offers`). Cada oferta indica se está vencendo a buybox (`is_buybox_winner`), o preço unitário e o estoque já convertido para a unidade de venda da opção (`quantity_multiplier` — ex.: opção "50 un" divide o estoque do SKU por 50).
        
        A paginação vem aninhada em `data.meta.pagination`. O campo `options` é um espelho de `variations` (mesmo conteúdo).
      security:
        - bearer: []
      parameters:
        - name: search
          in: query
          required: false
          description: Busca textual no título do anúncio.
          schema:
            type: string
            example: caneta
        - name: seller_sku
          in: query
          required: false
          description: Filtra pelas ofertas de um SKU específico.
          schema:
            type: string
            example: CAN-AZ-50
        - name: offer_status
          in: query
          required: false
          description: Status da oferta.
          schema:
            type: string
            enum:
              - active
              - paused
              - inactive
              - pending
        - name: is_buybox_winner
          in: query
          required: false
          description: "`true`: apenas anúncios com ofertas suas vencendo a buybox."
          schema:
            type: boolean
            example: true
        - name: per_page
          in: query
          required: false
          description: Itens por página. Default `15`.
          schema:
            type: integer
            default: 15
            example: 15
        - name: page
          in: query
          required: false
          schema:
            type: integer
            example: 1
      responses:
        "200":
          description: Ofertas listadas
          content:
            "application/json":
              example:
                success: true
                message_code: SUCCESS
                data:
                  meta:
                    search_query: ""
                    filters: []
                    pagination:
                      page: 1
                      per_page: 15
                      last_page: 1
                      has_prev_page: false
                      has_next_page: false
                      records:
                        from: 1
                        to: 1
                        records: 1
                  data:
                    - item_id: SAM-0000000000021
                      title: Caneta Esferográfica Azul 1.0mm
                      status: active
                      type: catalog
                      thumbnail_id: 01JD2R8KQX5VTWMA3B7YCE9FGH
                      images:
                        - id: 01JD2R8KQX5VTWMA3B7YCE9FGH
                          resources:
                            - name: sm
                              url: https://cdn.exemplo.com/images/caneta-sm.webp
                      has_variations: true
                      variations:
                        - id: 01JD4A0B1C2D3E4F5G6H7J8K9N
                          uid: 01JD4A0B1C2D3E4F5G6H7J8K9N
                          option_id: 01JD4A0B1C2D3E4F5G6H7J8K9N
                          description: "Quantidade: 50 un"
                          attributes:
                            - attribute_id: 19
                              attribute_name: Quantidade
                              value: "50"
                              unit: un
                              is_calculable: true
                          images: []
                          type: option
                          buybox_offers:
                            - uid: 01JD5B2C3D4E5F6G7H8J9K0M1N
                              id: 01JD5B2C3D4E5F6G7H8J9K0M1N
                              seller_sku: CAN-AZ-50
                              status: active
                              is_buybox_winner: true
                              last_buybox_calculation: "2026-06-09T13:05:22-03:00"
                              publication_variation_id: 01JD4A0B1C2D3E4F5G6H7J8K9N
                              price_data:
                                price: 24.9
                              stock_data:
                                quantity: 2
                                available_quantity: 2
                              unit_price: 24.9
                              price_from: 1245
                              quantity: 2
                              quantity_multiplier: 50
                      frontend_sync_status: synced
                      last_frontend_sync_at: "2026-06-09 10:21:44"
                      options:
                        - id: 01JD4A0B1C2D3E4F5G6H7J8K9N
                          uid: 01JD4A0B1C2D3E4F5G6H7J8K9N
                          option_id: 01JD4A0B1C2D3E4F5G6H7J8K9N
                          description: "Quantidade: 50 un"
                          attributes:
                            - attribute_id: 19
                              attribute_name: Quantidade
                              value: "50"
                              unit: un
                              is_calculable: true
                          images: []
                          type: option
                          buybox_offers:
                            - uid: 01JD5B2C3D4E5F6G7H8J9K0M1N
                              id: 01JD5B2C3D4E5F6G7H8J9K0M1N
                              seller_sku: CAN-AZ-50
                              status: active
                              is_buybox_winner: true
                              last_buybox_calculation: "2026-06-09T13:05:22-03:00"
                              publication_variation_id: 01JD4A0B1C2D3E4F5G6H7J8K9N
                              price_data:
                                price: 24.9
                              stock_data:
                                quantity: 2
                                available_quantity: 2
                              unit_price: 24.9
                              price_from: 1245
                              quantity: 2
                              quantity_multiplier: 50
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "422":
          "$ref": "#/components/responses/ValidationError"
components:
  securitySchemes:
    integrationToken:
      type: http
      scheme: bearer
      description: "Token de Integração da loja (formato: sk_...). Criado em Configurações → Tokens de Integração no painel do seller."
  schemas:
    Product:
      type: object
      properties:
        id:
          type: string
          description: ID do produto (26 caracteres)
        name:
          type: string
        sku:
          type: string
        price_type:
          type: string
          enum:
            - default
            - wholesale
        base_unit:
          type: string
          enum:
            - un
            - kg
            - pc
            - cx
            - pct
            - lt
            - mt
            - m2
            - m3
        dimensions:
          type: object
          properties:
            width:
              type: number
              description: Largura em cm
            height:
              type: number
              description: Altura em cm
            length:
              type: number
              description: Comprimento em cm
            weight:
              type: number
              description: Peso em kg
        is_available_for_sale:
          type: boolean
          description: Indica se o produto está disponível para venda
          default: true
        is_industrializable:
          type: boolean
          description: Indica se o produto pode ser fabricado sob demanda
        auto_wholesale_pricing:
          type: boolean
          description: Indica se os preços das faixas de atacado são derivados automaticamente do percentual de desconto
        allow_sale_without_stock:
          type: boolean
          description: Permite venda sem estoque disponível (pedido sob encomenda)
        dimensions_formatted:
          type: object
          nullable: true
          description: Dimensões formatadas para exibição (somente se include_dimensions_formatted=true)
          properties:
            width:
              type: string
              nullable: true
              example: 10,00 cm
            height:
              type: string
              nullable: true
              example: 10,00 cm
            length:
              type: string
              nullable: true
              example: 10,00 cm
            weight:
              type: string
              nullable: true
              example: 500g
        quantity:
          type: number
          description: Quantidade total em estoque
        reserved_quantity:
          type: number
          description: Quantidade reservada
        available_quantity:
          type: number
          description: Quantidade disponível para venda (quantity - reserved_quantity)
        price:
          type: number
          description: Preço de venda (somente para price_type=default)
        min_price:
          type: number
          description: Menor preço entre as faixas (somente para price_type=wholesale)
        max_price:
          type: number
          description: Maior preço entre as faixas (somente para price_type=wholesale)
        thumbnail:
          type: object
          nullable: true
          description: Imagem de destaque do produto (variantes thumbnail e md)
          properties:
            id:
              type: string
              description: ID da imagem
            resources:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
                    description: Nome da variante (thumbnail, sm, md, lg)
                  size:
                    type: string
                    description: "Dimensões da variante (ex: 400x400)"
                  url:
                    type: string
                    format: uri
    ProductInput:
      type: object
      required:
        - name
        - sku
        - base_unit
        - price_type
        - dimensions
      properties:
        name:
          type: string
          maxLength: 255
        sku:
          type: string
          maxLength: 50
          description: Deve ser único por loja
        base_unit:
          type: string
          enum:
            - un
            - kg
            - pc
            - cx
            - pct
            - lt
            - mt
            - m2
            - m3
        price_type:
          type: string
          enum:
            - default
            - wholesale
        is_available_for_sale:
          type: boolean
          default: true
        is_industrializable:
          type: boolean
          nullable: true
        allow_sale_without_stock:
          type: boolean
          nullable: true
          description: Permite venda sem estoque disponível (pedido sob encomenda)
        auto_wholesale_pricing:
          type: boolean
          description: Opcional. Deriva automaticamente os preços das faixas de atacado a partir do percentual de desconto
        dimensions:
          type: object
          required:
            - width
            - height
            - length
            - weight
          properties:
            width:
              type: number
              minimum: 0.001
              description: Largura em cm
            height:
              type: number
              minimum: 0.001
              description: Altura em cm
            length:
              type: number
              minimum: 0.001
              description: Comprimento em cm
            weight:
              type: number
              minimum: 0.001
              description: Peso em kg
    ProductUpdateInput:
      type: object
      description: Corpo da atualização de produto. Diferente da criação, o `sku` não é aceito (é ignorado se enviado) e apenas `name` e `dimensions` são obrigatórios.
      required:
        - name
        - dimensions
      properties:
        name:
          type: string
          maxLength: 255
        base_unit:
          type: string
          description: Opcional. Mantém o valor atual quando omitido
          enum:
            - un
            - kg
            - pc
            - cx
            - pct
            - lt
            - mt
            - m2
            - m3
        price_type:
          type: string
          description: Opcional. Veja as regras de troca na descrição do endpoint
          enum:
            - default
            - wholesale
        is_available_for_sale:
          type: boolean
          description: Opcional
        is_industrializable:
          type: boolean
          description: Opcional
        allow_sale_without_stock:
          type: boolean
          description: Opcional. Permite venda sem estoque disponível (pedido sob encomenda)
        auto_wholesale_pricing:
          type: boolean
          description: Opcional. Deriva automaticamente os preços das faixas de atacado a partir do percentual de desconto
        dimensions:
          type: object
          required:
            - width
            - height
            - length
            - weight
          properties:
            width:
              type: number
              minimum: 0.001
              description: Largura em cm
            height:
              type: number
              minimum: 0.001
              description: Altura em cm
            length:
              type: number
              minimum: 0.001
              description: Comprimento em cm
            weight:
              type: number
              minimum: 0.001
              description: Peso em kg
    Price:
      type: object
      properties:
        value:
          type: number
          description: Valor unitário da faixa
        min_quantity:
          type: integer
          description: Quantidade mínima para a faixa valer
        discount_percent:
          type: number
          nullable: true
          description: Percentual de desconto da faixa em relação ao preço-base (usado no atacado automático)
        package_weight:
          type: number
          nullable: true
          description: Peso da embalagem da faixa em kg
        package_height:
          type: number
          nullable: true
          description: Altura da embalagem da faixa em cm
        package_width:
          type: number
          nullable: true
          description: Largura da embalagem da faixa em cm
        package_length:
          type: number
          nullable: true
          description: Comprimento da embalagem da faixa em cm
    Stock:
      type: object
      properties:
        location_stock:
          type: object
          properties:
            location_id:
              type: string
              description: ID do local de estoque
            store_id:
              type: string
              description: ID da loja
            name:
              type: string
            status:
              type: string
              enum:
                - available
                - unavailable
            location_type:
              type: string
              enum:
                - seller_location
                - fulfillment
            allows_pickup:
              type: boolean
              description: Local permite retirada
            allows_production:
              type: boolean
              description: Local permite produção sob demanda
        quantity:
          type: number
        reserved_quantity:
          type: number
        available_quantity:
          type: number
    PaginationMeta:
      type: object
      properties:
        search_query:
          type: string
        filters:
          type: array
          items:
            type: string
        pagination:
          type: object
          properties:
            page:
              type: integer
            per_page:
              type: integer
            last_page:
              type: integer
            has_prev_page:
              type: boolean
            has_next_page:
              type: boolean
            records:
              type: object
              properties:
                from:
                  type: integer
                to:
                  type: integer
                records:
                  type: integer
    PriceInput:
      type: object
      properties:
        price:
          type: number
          nullable: true
          description: Valor monetário da faixa. Obrigatório na precificação manual (se omitido vira 0). Em produtos `wholesale` com `auto_wholesale_pricing` ligado é ignorado nas faixas `min_quantity >= 2` — o preço é calculado a partir do preço base e do `discount_percent`.
        min_quantity:
          type: integer
          default: 1
          description: "Quantidade mínima para ativar este preço (Padrão: 1). Produtos `default` só aceitam `min_quantity = 1`."
        discount_percent:
          type: number
          nullable: true
          minimum: 0
          description: Percentual de desconto sobre o preço base unitário (0 a menos de 100). Usado nas faixas de atacado automáticas; os descontos precisam ser progressivos (faixa de quantidade maior exige desconto maior).
          exclusiveMaximum: 100
        package_weight:
          type: number
          nullable: true
          minimum: 0.001
          description: Peso da embalagem fechada, em kg. Faz parte das medidas obrigatórias das faixas de atacado (`min_quantity >= 2`).
        package_height:
          type: number
          nullable: true
          minimum: 0.01
          description: Altura da embalagem fechada, em cm. Faz parte das medidas obrigatórias das faixas de atacado.
        package_width:
          type: number
          nullable: true
          minimum: 0.01
          description: Largura da embalagem fechada, em cm. Faz parte das medidas obrigatórias das faixas de atacado.
        package_length:
          type: number
          nullable: true
          minimum: 0.01
          description: Comprimento da embalagem fechada, em cm. Faz parte das medidas obrigatórias das faixas de atacado.
    ProductStockOverview:
      type: object
      properties:
        total:
          type: integer
          description: Quantidade total de estoque somando todas as localizações.
          example: 150
        stocks:
          type: array
          description: Lista detalhada de estoque do produto em cada localização.
          items:
            "$ref": "#/components/schemas/ProductStockDetail"
        locations:
          type: array
          description: Lista de todas as localizações disponíveis para a loja.
          items:
            "$ref": "#/components/schemas/LocationStock"
    ProductStock:
      type: object
      properties:
        id:
          type: integer
          description: Identificador interno do registro de estoque.
          example: 321
        product_id:
          type: string
          description: ID do produto.
          example: 01H81AV32307PVBSV4RXF15EK9
        location_id:
          type: string
          description: ID da localização de estoque.
          example: 01H81AV32307PVBSV4RXF15LOC
        quantity:
          type: integer
          description: Quantidade atual em estoque.
          example: 50
        reserved_quantity:
          type: integer
          description: Quantidade reservada (não disponível para venda imediata).
          example: 0
        available_quantity:
          type: integer
          description: Quantidade disponível para venda (quantity - reserved_quantity).
          example: 50
    ProductStockDetail:
      type: object
      description: Registro de estoque do produto em uma localização, com o produto e o local aninhados.
      properties:
        id:
          type: integer
          description: Identificador interno do registro de estoque.
          example: 321
        product_sku:
          type: object
          description: Dados do produto (id, name, sku, base_unit, dimensions, flags de venda, prices, totais de estoque, thumbnail e images).
        location_stock:
          "$ref": "#/components/schemas/LocationStock"
        quantity:
          type: integer
          description: Quantidade física nesta localização.
          example: 100
        reserved_quantity:
          type: integer
          description: Quantidade reservada em carrinhos/pedidos abertos.
          example: 5
        available_quantity:
          type: integer
          description: Quantidade disponível para venda (quantity - reserved_quantity).
          example: 95
    LocationStock:
      type: object
      properties:
        location_id:
          type: string
          description: ID da localização.
          example: 01H81AV32307PVBSV4RXF15LOC
        store_id:
          type: integer
          description: Identificador interno da loja dona do local.
          example: 42
        name:
          type: string
          description: Nome da localização.
          example: Matriz - São Paulo
        status:
          type: string
          enum:
            - available
            - unavailable
          description: Status da localização.
          example: available
        location_type:
          type: string
          enum:
            - seller_location
            - fulfillment
          description: Tipo da localização.
          example: seller_location
        allows_pickup:
          type: boolean
          description: Indica se o local permite retirada em mãos.
          example: false
        allows_production:
          type: boolean
          description: Indica se o local permite produção sob demanda.
          example: false
    StockUpdateInput:
      type: object
      required:
        - location_id
        - quantity
      properties:
        location_id:
          type: string
          description: ID da localização onde o estoque será alterado.
          example: 01H81AV32307PVBSV4RXF15LOC
        quantity:
          type: integer
          minimum: 1
          description: Quantidade a ser definida, incrementada ou decrementada.
          example: 10
        increment:
          type: boolean
          description: Se verdadeiro, soma a quantidade ao estoque atual.
          default: false
          example: false
        decrement:
          type: boolean
          description: Se verdadeiro, subtrai a quantidade do estoque atual.
          default: false
          example: false
    SuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message_code:
          type: string
          example: SUCCESS
        data:
          type: object
        meta:
          type: object
          description: Presente apenas quando há metadados a retornar.
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        code:
          type: integer
          example: 400
        message_code:
          type: string
          example: BAD_REQUEST
        description:
          type: string
          example: Erro na requisição.
        data:
          type: array
          items: {}
          example: []
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
        meta:
          type: array
          items: {}
          example: []
    LocationStockInput:
      type: object
      required:
        - name
        - status
        - location_type
      properties:
        name:
          type: string
        status:
          type: string
          enum:
            - available
            - unavailable
          default: available
        location_type:
          type: string
          enum:
            - seller_location
          default: seller_location
        allows_pickup:
          type: boolean
          default: false
          description: Permite retirada no local
        allows_production:
          type: boolean
          default: false
          description: Permite producao sob demanda
        company_branch_uid:
          type: string
          nullable: true
          description: ID da filial a vincular ao local. Precisa ser uma filial ativa da empresa; omita para deixar o local respondendo pela matriz.
    Address:
      type: object
      properties:
        id:
          type: string
          description: ID do endereco
        uid:
          type: string
          description: Mesmo valor de id (mantido por compatibilidade)
        street:
          type: string
        number:
          type: string
        complement:
          type: string
          nullable: true
        reference:
          type: string
          nullable: true
          description: Ponto de referencia
        can_deliver_to_neighbor:
          type: boolean
          description: Se o entregador pode deixar com um vizinho
        delivery_instructions:
          type: string
          nullable: true
          description: Instrucoes de entrega
        district:
          type: string
        city:
          type: string
        state:
          type: string
        country:
          type: string
        zip_code:
          type: string
          description: CEP formatado (00000-000)
        latitude:
          type: number
        longitude:
          type: number
        place_id:
          type: string
          nullable: true
          description: Identificador do lugar no provedor de geocodificacao
        address_components:
          nullable: true
          description: Componentes estruturados do endereco retornados pelo provedor de geocodificacao
        full_address:
          type: string
          description: Endereco completo em uma unica linha
        is_complete:
          type: boolean
          description: Indica se o endereco ja possui coordenadas resolvidas
        type:
          type: string
          enum:
            - logistics
            - local_real
            - local_devolucao
          description: O tipo do endereco. Pelo menos um endereco do tipo 'logistics' e obrigatorio para o local de estoque operar.
        type_label:
          type: string
          nullable: true
          description: Rotulo legivel do tipo
    AddressInput:
      type: object
      required:
        - zip_code
        - street
        - number
        - district
        - city
        - state
        - type
      properties:
        zip_code:
          type: string
          description: CEP (apenas numeros ou com traco, formato 00000-000 ou 00000000)
        street:
          type: string
          minLength: 3
        number:
          type: string
          maxLength: 20
        complement:
          type: string
          nullable: true
          maxLength: 255
        reference:
          type: string
          nullable: true
          maxLength: 60
          description: Ponto de referencia
        can_deliver_to_neighbor:
          type: boolean
          nullable: true
          description: Se o entregador pode deixar com um vizinho
        delivery_instructions:
          type: string
          nullable: true
          maxLength: 150
          description: Instrucoes de entrega
        district:
          type: string
          minLength: 2
        city:
          type: string
          minLength: 2
        state:
          type: string
          minLength: 2
          maxLength: 2
        country:
          type: string
          minLength: 2
          maxLength: 2
          default: BR
        latitude:
          type: number
          nullable: true
          description: Se omitido, a plataforma tenta resolver as coordenadas pelo CEP ou por geocodificacao
        longitude:
          type: number
          nullable: true
        place_id:
          type: string
          nullable: true
        address_components:
          type: array
          nullable: true
          items: {}
        type:
          type: string
          enum:
            - logistics
            - local_real
            - local_devolucao
          description: "Tipo de endereco para este local. Valores validos: logistics, local_real, local_devolucao"
    AddressUpdateInput:
      type: object
      description: Mesmos campos do cadastro, porem todos opcionais — envie apenas o que quer alterar.
      properties:
        zip_code:
          type: string
          description: CEP (apenas numeros ou com traco, formato 00000-000 ou 00000000)
        street:
          type: string
          minLength: 3
        number:
          type: string
          maxLength: 20
        complement:
          type: string
          nullable: true
          maxLength: 255
        reference:
          type: string
          nullable: true
          maxLength: 60
        can_deliver_to_neighbor:
          type: boolean
          nullable: true
        delivery_instructions:
          type: string
          nullable: true
          maxLength: 150
        district:
          type: string
          minLength: 2
        city:
          type: string
          minLength: 2
        state:
          type: string
          minLength: 2
          maxLength: 2
        country:
          type: string
          minLength: 2
          maxLength: 2
        latitude:
          type: number
          nullable: true
        longitude:
          type: number
          nullable: true
        place_id:
          type: string
          nullable: true
        address_components:
          type: array
          nullable: true
          items: {}
        type:
          type: string
          nullable: true
          enum:
            - logistics
            - local_real
            - local_devolucao
          description: Novo tipo do vinculo do endereco com o local
    CategoriesResponse:
      type: object
      properties:
        success:
          type: boolean
        message_code:
          type: string
        data:
          type: array
          items:
            "$ref": "#/components/schemas/Category"
      required:
        - success
        - message_code
        - data
    Category:
      type: object
      properties:
        id:
          type: integer
          description: ID da categoria
        name:
          type: string
        description:
          type:
            - string
            - "null"
        departament:
          "$ref": "#/components/schemas/Department"
        parent:
          "$ref": "#/components/schemas/ParentCategory"
        is_visible:
          type: boolean
        priority:
          type: integer
        domain:
          type: string
        level:
          type: integer
        hierarchy:
          type: array
          description: Breadcrumb completo da categoria (cada nível com id e nome)
          items:
            "$ref": "#/components/schemas/HierarchyLevel"
        settings:
          type: array
          items: {}
        catalog_overrides:
          type:
            - object
            - "null"
        total_children:
          type: integer
        children:
          type: array
          description: Subcategorias (recursivo). Na busca, só voltam folhas — portanto vazio.
          items:
            "$ref": "#/components/schemas/Category"
      required:
        - id
        - name
        - departament
        - parent
    HierarchyLevel:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
      required:
        - id
        - name
    Department:
      type: object
      properties:
        id:
          type: integer
          description: ID do departamento
        name:
          type: string
        icon_svg:
          type:
            - string
            - "null"
      required:
        - id
        - name
    ParentCategory:
      type: object
      properties:
        id:
          type: integer
        parent_id:
          type:
            - integer
            - "null"
        name:
          type: string
        hierarchy:
          type: array
          items:
            "$ref": "#/components/schemas/HierarchyLevel"
      required:
        - id
        - parent_id
        - name
    CategoryAttributesResponse:
      type: object
      properties:
        success:
          type: boolean
        message_code:
          type: string
        data:
          type: array
          description: Com `matrix=true`, lista de grupos (`AttributeGroup`). Sem `matrix`, lista plana de atributos (`AttributeItem`).
          items:
            oneOf:
              - "$ref": "#/components/schemas/AttributeGroup"
              - "$ref": "#/components/schemas/AttributeItem"
      required:
        - success
        - message_code
        - data
    AttributeGroup:
      type: object
      properties:
        key:
          type:
            - string
            - "null"
          description: "Chave da matriz (ex: identification, appearance, technical). `null` para atributos sem matriz."
        label:
          type: string
        items:
          type: array
          items:
            "$ref": "#/components/schemas/AttributeItem"
      required:
        - key
        - label
        - items
    AttributeItem:
      type: object
      properties:
        id:
          type: integer
          description: ID do vínculo categoria-atributo
        attribute_id:
          type: integer
          description: ID do atributo
        category_id:
          type: integer
          description: ID da categoria
        is_required:
          type: boolean
          description: Indica se o atributo e obrigatorio para a categoria
        is_feature:
          type: boolean
          description: Indica se e uma caracteristica do produto
        is_variant:
          type: boolean
          description: Indica se e um atributo de variacao
        is_combinable:
          type: boolean
          description: Indica se pode ser usado em combinacoes para variacoes
        is_filter:
          type: boolean
          description: Indica se o atributo aparece como filtro na vitrine
        attribute_data:
          "$ref": "#/components/schemas/AttributeData"
      required:
        - id
        - attribute_id
        - category_id
        - is_required
        - is_feature
        - is_variant
        - is_combinable
        - is_filter
    AttributeData:
      type: object
      description: "Definição do atributo. O bloco `value_definition` é autodescritivo: traz os campos esperados (`fields`), as opções pré-cadastradas (`options`, quando houver) e as unidades disponíveis."
      properties:
        id:
          type: integer
          description: ID do atributo
        name:
          type: string
        type:
          type: string
          enum:
            - default
            - default_unit
            - default_list
            - dimension_3d
            - dimension_2d
            - color
            - image
            - brand
            - packaging
          description: Tipo estrutural do atributo. `default_unit` exige `unit`; `dimension_2d/3d` exigem width/height(/depth)+unit; `color` aceita opção pré-cadastrada ou cor customizada (value + hex).
        value_type:
          type:
            - string
            - "null"
          enum:
            - text
            - float
            - number
            - date
            - boolean
            - select
            - radio
            - checkbox
            - null
          description: Tipo do valor para atributos default. Tipos especializados (color, image, brand, packaging) ignoram este campo.
        is_feature:
          type: boolean
        is_variant:
          type: boolean
        is_calculable:
          type: boolean
          description: "Atributo usado em cálculos (ex: Quantidade, que precisa casar com a unidade base do SKU)"
        domain:
          type:
            - string
            - "null"
        ui:
          type: object
          properties:
            public_name:
              type:
                - string
                - "null"
            description:
              type:
                - string
                - "null"
            matrix:
              type:
                - string
                - "null"
              description: Matriz de organização (identification, appearance, technical, dimensions, ...)
            select_type:
              type: string
              enum:
                - select
                - radio
                - checkbox
                - text
              description: Como o valor é escolhido. `text` = digitação livre; os demais exigem opção pré-cadastrada (exceto atributos de cor, que aceitam cor customizada).
        value_definition:
          type: object
          properties:
            fields:
              type: object
              description: Schema dos campos esperados no valor (montagem dinâmica de formulário)
            options:
              type: array
              description: Opções pré-cadastradas (presente apenas quando o atributo tem opções)
              items:
                "$ref": "#/components/schemas/AttributeOption"
            default_unit:
              type:
                - string
                - "null"
            available_units:
              type: array
              items:
                type: string
    AttributeOption:
      type: object
      properties:
        id:
          type: integer
          description: ID da opção (use em `value_id` ao criar o anúncio)
        attribute_id:
          type: integer
        value:
          type: string
        component:
          type: object
          description: "Payload visual da opção, varia por tipo de atributo. Para cor: `{ value, main_color, hex, brightness }`."
          additionalProperties: true
        position:
          type: integer
        is_default:
          type: boolean
      required:
        - id
        - attribute_id
        - value
        - component
        - position
        - is_default
    AttributeCombinationsResponse:
      type: object
      properties:
        success:
          type: boolean
        message_code:
          type: string
        data:
          type: object
          properties:
            combinations:
              type: array
              items:
                "$ref": "#/components/schemas/AttributeCombination"
            primary_attribute:
              "$ref": "#/components/schemas/PrimaryAttributeInfo"
          required:
            - combinations
            - primary_attribute
      required:
        - success
        - message_code
        - data
    AttributeCombination:
      type: object
      properties:
        attributes:
          type: array
          items:
            "$ref": "#/components/schemas/CombinationAttribute"
        attributes_details:
          type: object
          additionalProperties:
            type: string
        description:
          type: string
      required:
        - attributes
        - attributes_details
        - description
    CombinationAttribute:
      type: object
      properties:
        attribute_id:
          type: integer
          description: ID do atributo
        attribute_name:
          type: string
        value:
          type: string
        unit:
          type: string
          description: Unidade de medida (presente apenas quando aplicável)
        hex:
          type: string
          description: Cor em hexadecimal (presente apenas para atributos de cor)
        main_color:
          type: string
          description: Cor principal (presente apenas para atributos de cor)
        brightness:
          type: string
          enum:
            - light
            - dark
          description: Luminosidade calculada da cor (presente apenas para atributos de cor)
        width:
          type:
            - string
            - number
          description: Largura (presente apenas para atributos de dimensão)
        height:
          type:
            - string
            - number
          description: Altura (presente apenas para atributos de dimensão)
      required:
        - attribute_id
        - attribute_name
        - value
    PrimaryAttributeInfo:
      type: object
      description: Atributo principal das combinações — facilita organizar fotos por variação no front.
      properties:
        id:
          type: integer
          description: ID do atributo principal
        name:
          type:
            - string
            - "null"
        has_options:
          type: boolean
        default_unit:
          type:
            - string
            - "null"
        values:
          type: array
          items:
            type: object
            properties:
              value:
                type: string
              label:
                type: string
              hex:
                type: string
              main_color:
                type: string
              brightness:
                type: string
            required:
              - value
              - label
      required:
        - id
        - name
        - has_options
        - default_unit
        - values
    CreateAdvertisementRequest:
      type: object
      description: É obrigatório informar `seller_sku` (anúncio sem variações) ou `variations` — um dos dois precisa estar presente. Os SKUs devem existir previamente na loja.
      properties:
        title:
          type: string
          maxLength: 100
          description: Titulo do anuncio
        category_id:
          type: integer
          description: ID da categoria selecionada (precisa ser categoria folha existente)
        gtin:
          "$ref": "#/components/schemas/GTIN"
        seller_sku:
          type:
            - string
            - "null"
          description: SKU do produto para anúncio sem variações. Obrigatório quando `variations` não for enviado. O SKU precisa existir na loja.
        attributes:
          type: array
          items:
            "$ref": "#/components/schemas/AdvertisementAttribute"
          description: Atributos de caracteristicas do produto. Obrigatório quando a categoria possui atributos com `is_required=true`.
        variations:
          type: array
          items:
            "$ref": "#/components/schemas/AdvertisementVariation"
          description: Variacoes do produto. Obrigatório quando `seller_sku` não for enviado.
        images:
          type: array
          items:
            "$ref": "#/components/schemas/ImageReference"
          description: Imagens do anuncio principal. Opcional na criação, mas o checklist exige pelo menos uma imagem para publicar.
        description:
          "$ref": "#/components/schemas/PublicationDescription"
          description: Descrição longa do anúncio. Opcional. Pode ser informada na criação ou depois via PUT /api/items/{id}/description.
        technical_sheets:
          type: array
          items:
            "$ref": "#/components/schemas/TechnicalSheetInput"
          description: Fichas técnicas do anúncio. Opcionais. Também podem ser criadas ou editadas depois via /api/items/{id}/technical-sheets.
      required:
        - title
        - category_id
    PublicationDescription:
      type: object
      description: Aceita um objeto `{ layout, raw_content }` ou uma string simples (legado, equivale a `layout=markdown`).
      properties:
        layout:
          type: string
          enum:
            - text
            - html
            - markdown
          description: "Formato do `raw_content`. Default: `markdown`."
        raw_content:
          type: string
          description: Conteúdo bruto da descrição no formato indicado por `layout`.
    TechnicalSheetInput:
      type: object
      required:
        - type
        - title
      properties:
        type:
          type: string
          enum:
            - technical_specification
            - characteristics
            - materials
            - installation
            - maintenance
            - safety
            - environmental
            - custom
          description: Tipo da ficha técnica.
        title:
          type: string
          maxLength: 255
          description: Título exibido para a seção da ficha.
        items:
          type: array
          items:
            type: object
            required:
              - item_key
              - item_value
            properties:
              item_key:
                type: string
                maxLength: 255
              item_value:
                type: string
                maxLength: 1000
              display_order:
                type: integer
                minimum: 0
    GTIN:
      type: object
      properties:
        type:
          type:
            - integer
            - string
          enum:
            - 8
            - 12
            - 13
            - 14
            - "8"
            - "12"
            - "13"
            - "14"
          description: "Tipo de GTIN: 8, 12, 13 ou 14 dígitos (13 para EAN-13). Nas respostas, vem como string."
        value:
          type: string
          description: Numero do codigo de barras
    AdvertisementAttribute:
      type: object
      description: "Valor de um atributo do anúncio. Campos extras dependem do tipo do atributo: cor customizada usa `hex`/`main_color`/`brightness`; dimensões usam `width`/`height`/`depth` + `unit`; listas usam `items`."
      properties:
        id:
          type: integer
          description: ID do atributo
        value_id:
          type:
            - integer
            - "null"
          description: ID da opção selecionada (para atributos com opcoes pré-cadastradas)
        option_id:
          type:
            - integer
            - "null"
          description: Alias aceito para `value_id`
        value:
          type:
            - string
            - integer
            - "null"
          description: Valor do atributo
        unit:
          type:
            - string
            - "null"
          description: Unidade de medida (obrigatória em atributos do tipo default_unit; precisa estar em available_units)
        hex:
          type:
            - string
            - "null"
          description: "Cor customizada em hexadecimal (#RGB ou #RRGGBB). Para atributos de cor, `value` (nome da cor) + `hex` válido dispensam opção pré-cadastrada."
        main_color:
          type:
            - string
            - "null"
          description: "Cor principal da cor customizada (ex: Vermelho)"
        brightness:
          type:
            - string
            - "null"
          description: Luminosidade da cor (light/dark). Se omitido, é calculada a partir do hex.
        width:
          type:
            - string
            - number
            - "null"
          description: Largura (atributos dimension_2d/dimension_3d)
        height:
          type:
            - string
            - number
            - "null"
          description: Altura (atributos dimension_2d/dimension_3d)
        depth:
          type:
            - string
            - number
            - "null"
          description: Profundidade (atributos dimension_3d)
        fields:
          type:
            - object
            - "null"
          description: "Forma alternativa de enviar dimensões: `{ width, height, depth, unit }`"
          properties:
            width: {}
            height: {}
            depth: {}
            unit:
              type: string
        items:
          type:
            - array
            - "null"
          description: Itens do atributo (obrigatório em atributos do tipo default_list)
    AdvertisementVariation:
      type: object
      properties:
        seller_sku:
          type: string
          description: SKU do produto para esta variacao (precisa existir na loja)
        attributes:
          type: array
          items:
            "$ref": "#/components/schemas/VariationAttribute"
          description: Atributos que definem esta variacao
        images:
          type: array
          items:
            "$ref": "#/components/schemas/ImageReference"
          description: Imagens especificas desta variacao
      required:
        - seller_sku
    VariationAttribute:
      type: object
      description: Informe `attribute_id` e `value` (ou `value_id` para opção pré-cadastrada). Atributos de cor aceitam cor customizada com `value` + `hex` (+ `main_color`/`brightness` opcionais), sem opção pré-cadastrada.
      properties:
        attribute_id:
          type: integer
          description: ID do atributo
        attribute_name:
          type:
            - string
            - "null"
        value:
          type:
            - string
            - integer
            - "null"
        unit:
          type:
            - string
            - "null"
        value_id:
          type:
            - integer
            - "null"
          description: ID da opção pré-cadastrada
        option_id:
          type:
            - integer
            - "null"
          description: Alias aceito para `value_id`
        hex:
          type:
            - string
            - "null"
          description: "Cor customizada em hexadecimal (#RGB ou #RRGGBB)"
        main_color:
          type:
            - string
            - "null"
        brightness:
          type:
            - string
            - "null"
        width:
          type:
            - string
            - number
            - "null"
        height:
          type:
            - string
            - number
            - "null"
        depth:
          type:
            - string
            - number
            - "null"
        fields:
          type:
            - object
            - "null"
          description: "Forma alternativa de enviar dimensões: `{ width, height, depth, unit }`"
    ImageReference:
      type: object
      properties:
        id:
          type: string
          description: ID da imagem (UUID retornado por POST /api/media/upload)
      required:
        - id
    SimulatedAdvertisementResponse:
      type: object
      properties:
        success:
          type: boolean
        message_code:
          type: string
        data:
          "$ref": "#/components/schemas/CreatedAdvertisementData"
      required:
        - success
        - message_code
        - data
    CreatedAdvertisementResponse:
      type: object
      properties:
        success:
          type: boolean
        message_code:
          type: string
        data:
          "$ref": "#/components/schemas/CreatedAdvertisementData"
      required:
        - success
        - message_code
        - data
    CreatedAdvertisementData:
      type: object
      description: Objeto do anúncio, retornado por create, publish e simulate.
      properties:
        item_id:
          type: string
          description: "ID do anúncio: prefixo da plataforma + 13 dígitos (ex: SAM-0000000000007)"
        title:
          type: string
        short_description:
          type:
            - string
            - "null"
        slug:
          type:
            - string
            - "null"
        type:
          allOf:
            - "$ref": "#/components/schemas/TypeValue"
          description: "Tipo do anúncio: `default` (Padrão) ou `catalog` (Catálogo)"
        status:
          allOf:
            - "$ref": "#/components/schemas/StatusValue"
          description: "Status do anúncio: `draft`, `pending_review`, `active`, `paused` ou `inactive`"
        seller_sku:
          type:
            - string
            - "null"
          description: SKU vinculado diretamente ao anúncio (quando não há variações)
        price_range:
          type:
            - array
            - "null"
          description: Faixa de preço calculada a partir das ofertas (pode ser null em rascunhos)
        score:
          type:
            - integer
            - "null"
          description: Score de qualidade do anúncio
        campaigns:
          type: array
        pricing_context:
          type: array
          description: Contexto de precificação por faixa de quantidade (descontos, campanhas)
        frontend_sync_status:
          type: string
          description: "Status de sincronização com a vitrine (ex: pending)"
        last_frontend_sync_at:
          type:
            - string
            - "null"
          description: Formato Y-m-d H:i:s
        submitted_for_review_at:
          type:
            - string
            - "null"
          description: Quando o anúncio foi enviado para revisão. Formato Y-m-d H:i:s
        reviewed_at:
          type:
            - string
            - "null"
          description: Quando a plataforma revisou o anúncio. Formato Y-m-d H:i:s
        rejection_reason:
          type:
            - string
            - "null"
          description: Motivo da rejeição quando o anúncio volta para rascunho
        gtin:
          allOf:
            - "$ref": "#/components/schemas/GTIN"
          description: Presente apenas quando informado
        store:
          allOf:
            - "$ref": "#/components/schemas/Store"
          description: Loja dona do anúncio (presente quando carregada)
        department:
          "$ref": "#/components/schemas/Department"
        category:
          "$ref": "#/components/schemas/CategoryRef"
        thumbnail:
          type:
            - object
            - "null"
          description: "Miniatura no tamanho `sm`: `{ id, resource }`"
        images:
          type: array
          items:
            "$ref": "#/components/schemas/Image"
        attributes:
          type: array
          items:
            "$ref": "#/components/schemas/PublicationAttributeOut"
        variations:
          type: array
          items:
            "$ref": "#/components/schemas/PublicationVariationOut"
      required:
        - item_id
        - title
        - type
        - status
        - department
        - category
        - images
        - attributes
        - variations
    Image:
      type: object
      properties:
        id:
          type: string
          description: ID da imagem (UUID)
        resources:
          type: array
          description: Variações de tamanho da imagem (`{ name, url, ... }`)
          items:
            type: object
      required:
        - id
        - resources
    PublicationAttributeOut:
      type: object
      properties:
        attribute_id:
          type: integer
          description: ID do atributo
        attribute_name:
          type:
            - string
            - "null"
        attribute_value:
          type:
            - string
            - integer
            - "null"
        value_unit:
          type:
            - string
            - "null"
        value_id:
          type:
            - integer
            - "null"
        component:
          type:
            - object
            - "null"
          description: "Payload visual do valor. Para cor: `{ value, main_color, hex, brightness }`."
      required:
        - attribute_id
        - attribute_name
        - attribute_value
        - value_unit
        - value_id
        - component
    PublicationVariationOut:
      type: object
      description: Variação do anúncio. Em anúncios padrão o identificador vem como `offer_id`; em anúncios de catálogo, como `option_id`.
      properties:
        offer_id:
          type: string
          description: ID da variação (26 caracteres). Presente em anúncios padrão.
        option_id:
          type: string
          description: ID da opção de catálogo (26 caracteres). Presente em anúncios de catálogo.
        description:
          type: string
          description: "Descrição legível da combinação (ex: Voltagem: 110 V, Cor: Azul)"
        attributes:
          type: array
          description: Atributos da variação (`{ attribute_id, attribute_name, value, unit?, value_id?, hex?, main_color?, brightness? }`)
          items:
            type: object
        status:
          type: string
          enum:
            - active
            - pending
            - hidden
          description: Status da variação
        type:
          type: string
          enum:
            - offer
            - option
        images:
          type: array
          items:
            "$ref": "#/components/schemas/Image"
        seller_sku:
          type:
            - string
            - "null"
          description: Presente quando `type=offer`
        offer:
          "$ref": "#/components/schemas/OfferData"
      required:
        - description
        - attributes
        - status
        - type
        - images
        - offer
    OfferData:
      type: object
      properties:
        price_type:
          type: string
          description: "Tipo de precificação (ex: default, wholesale)"
        price_from:
          type: number
          description: Preço "De" quando há desconto
        prices:
          type: array
          description: Faixas de preço (atacado)
          items:
            type: object
        quantity:
          type: integer
        price:
          type: number
          description: Preço "Por"
        original_price:
          type:
            - number
            - "null"
        has_discount:
          type: boolean
        discount_percent:
          type: integer
        wholesale_tiers:
          type: array
          description: Presente apenas quando há faixas de atacado
          items:
            type: object
        buybox:
          type: object
          description: Dados da buybox (presente apenas em anúncios de catálogo)
      required:
        - price_type
        - price_from
        - prices
        - quantity
        - price
        - original_price
        - has_discount
        - discount_percent
    TypeValue:
      type: object
      properties:
        value:
          type: string
          enum:
            - default
            - catalog
        label:
          type: string
      required:
        - value
        - label
    StatusValue:
      type: object
      properties:
        value:
          type: string
          enum:
            - draft
            - pending_review
            - active
            - paused
            - inactive
        label:
          type: string
      required:
        - value
        - label
    Store:
      type: object
      properties:
        store_id:
          type: string
          description: ID da loja (26 caracteres)
        store_name:
          type: string
        store_code:
          type: string
        store_status:
          type: string
        store_url:
          type:
            - string
            - "null"
        store_type:
          type: string
        commission_table_id:
          type:
            - integer
            - string
            - "null"
          description: ID da tabela de comissão
        max_locations:
          type:
            - integer
            - "null"
        features:
          type: array
        company:
          type: object
          description: Dados cadastrais da empresa
        shares_products:
          type: boolean
        shares_stock_locations:
          type: boolean
        shares_logistics:
          type: boolean
        is_primary:
          type: boolean
        primary_store:
          type:
            - object
            - "null"
      required:
        - store_id
        - store_name
        - store_code
    CategoryRef:
      type: object
      properties:
        id:
          type: integer
          description: ID da categoria
        parent_id:
          type:
            - integer
            - "null"
        name:
          type: string
        hierarchy:
          type: array
          items:
            "$ref": "#/components/schemas/HierarchyLevel"
      required:
        - id
        - parent_id
        - name
    AttachSKURequest:
      type: object
      properties:
        seller_sku:
          type: string
          maxLength: 64
          description: SKU do produto a vincular. Precisa pertencer (ou estar associado) à loja autenticada.
        status:
          type: string
          description: "Status inicial da oferta. Default: `active`."
          enum:
            - active
            - paused
            - inactive
      required:
        - seller_sku
    AttachedSKUResponse:
      type: object
      properties:
        success:
          type: boolean
        message_code:
          type: string
        data:
          "$ref": "#/components/schemas/AttachedSKUData"
      required:
        - success
        - message_code
        - data
    AttachedSKUData:
      type: object
      properties:
        offer_id:
          type: string
          description: ID da oferta criada (26 caracteres). Use em PUT/DELETE /api/items/catalog/offers/{offerId}.
        seller_sku:
          type: string
        status:
          type: string
          enum:
            - active
            - paused
            - inactive
            - pending
        is_buybox_winner:
          type: boolean
          description: Recalculado em background após o vínculo — costuma vir `false` na resposta imediata
        last_buybox_calculation:
          type:
            - string
            - "null"
        price_data:
          "$ref": "#/components/schemas/PriceData"
        stock_data:
          "$ref": "#/components/schemas/StockData"
        publication:
          type:
            - object
            - "null"
          description: Resumo do anúncio de catálogo
          properties:
            item_id:
              type: string
              description: ID do anúncio
            title:
              type: string
            status:
              type: string
            type:
              type: string
            thumbnail_id:
              type:
                - string
                - "null"
              description: ID da imagem de capa (UUID)
        option:
          "$ref": "#/components/schemas/OptionData"
      required:
        - offer_id
        - seller_sku
        - status
        - is_buybox_winner
        - last_buybox_calculation
        - price_data
        - stock_data
        - publication
        - option
    PriceData:
      type: object
      description: "Snapshot de preço da oferta. Preço único: `{ price }`. Atacado: `{ type: \"wholesale\", tiers: [...] }`."
      properties:
        price:
          type: number
          description: Preço único (presente quando não há faixas de atacado)
        type:
          type: string
          enum:
            - wholesale
          description: Presente apenas quando há faixas de atacado
        tiers:
          type: array
          description: Faixas de preço por quantidade (presente apenas no atacado)
          items:
            "$ref": "#/components/schemas/PriceTier"
    PriceTier:
      type: object
      properties:
        min_quantity:
          type: integer
        price:
          type: number
      required:
        - min_quantity
        - price
    StockData:
      type: object
      properties:
        id:
          type: integer
          description: ID interno do registro de estoque
        product_id:
          type: string
          description: ID do SKU do produto (26 caracteres)
        location_id:
          type: string
          description: ID do local de estoque (26 caracteres)
        quantity:
          type: integer
        reserved_quantity:
          type: integer
        available_quantity:
          type: integer
      required:
        - id
        - product_id
        - location_id
        - quantity
        - reserved_quantity
        - available_quantity
    OptionData:
      type: object
      properties:
        uid:
          type: string
          description: ID da opção de catálogo (26 caracteres)
        description:
          type: string
        attributes:
          type: array
          items:
            "$ref": "#/components/schemas/OptionAttribute"
        type:
          type: string
          enum:
            - option
            - offer
        status:
          type: string
          enum:
            - active
            - pending
            - hidden
        images:
          type: array
          items:
            type: object
      required:
        - uid
        - description
        - attributes
        - type
        - status
        - images
    OptionAttribute:
      type: object
      properties:
        attribute_id:
          type: integer
          description: ID do atributo
        attribute_name:
          type: string
        value:
          type: string
        unit:
          type:
            - string
            - "null"
        value_id:
          type:
            - integer
            - "null"
      required:
        - attribute_id
        - attribute_name
        - value
    TechnicalSheet:
      type: object
      description: "Ficha técnica de um anúncio: lista ordenada de pares chave/valor agrupada por tipo (especificações, materiais, segurança etc.)."
      properties:
        sheet_id:
          type: string
          description: ID da ficha técnica (26 caracteres)
        publication_id:
          type: string
          description: "`item_id` do anúncio dono da ficha"
        type:
          type: object
          description: Tipo da ficha técnica
          properties:
            value:
              type: string
              enum:
                - technical_specification
                - characteristics
                - materials
                - installation
                - maintenance
                - safety
                - environmental
                - custom
            label:
              type: string
              description: "Rótulo amigável do tipo (ex.: Ficha Técnica, Materiais)"
            description:
              type: string
          required:
            - value
            - label
            - description
        title:
          type: string
          maxLength: 255
        items:
          type: array
          items:
            "$ref": "#/components/schemas/TechnicalSheetItem"
      required:
        - sheet_id
        - publication_id
        - type
        - title
        - items
    TechnicalSheetItem:
      type: object
      description: Linha da ficha técnica (par chave/valor).
      properties:
        item_id:
          type: string
          description: ID do item da ficha (26 caracteres)
        item_key:
          type: string
          maxLength: 255
          description: "Nome da característica (ex.: Potência)"
        item_value:
          type: string
          maxLength: 1000
          description: "Valor da característica (ex.: 650 W)"
        display_order:
          type: integer
          minimum: 0
          description: Posição de exibição (0 = primeiro)
      required:
        - item_id
        - item_key
        - item_value
        - display_order
    MediaCreatedResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message_code:
          type: string
          example: RESOURCE_CREATED
        data:
          "$ref": "#/components/schemas/MediaItem"
      required:
        - success
        - message_code
        - data
    MediaItemResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message_code:
          type: string
          example: SUCCESS
        data:
          "$ref": "#/components/schemas/MediaItem"
      required:
        - success
        - message_code
        - data
    MediaCollectionResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message_code:
          type: string
          example: SUCCESS
        data:
          type: object
          properties:
            meta:
              "$ref": "#/components/schemas/PaginationMeta"
            data:
              type: array
              items:
                "$ref": "#/components/schemas/MediaItem"
      required:
        - success
        - message_code
        - data
    MediaItem:
      type: object
      description: Objeto que representa uma imagem/mídia na API de seller. Campos internos de propriedade (`owner_id`, `owner_model`) ficam de fora do payload de propósito — você não precisa deles para integrar, então não vai encontrá-los aqui.
      properties:
        id:
          type: string
          description: Identificador único da imagem (26 caracteres). É o valor usado como `{file_hash}` nas rotas de detalhe e exclusão.
          example: 01JMZXZ72881MD2P37N2K97YJJ
        original_source:
          type: string
          format: uri
          description: URL da imagem original, já convertida para WebP em alta qualidade.
          example: https://cdn.example.com/products/2026/05/28/original_01JMZXZ72881MD2P37N2K97YJJ.webp
        urls:
          type: array
          description: "Variações de tamanho geradas automaticamente (todas em WebP). Uma entrada por variação: `thumbnail` (135x135), `sm` (200x200), `md` (400x400), `lg` (800x800) e `xl` (1600x1600)."
          items:
            type: object
            properties:
              name:
                type: string
                enum:
                  - thumbnail
                  - sm
                  - md
                  - lg
                  - xl
                description: Nome da variação de tamanho.
                example: thumbnail
              size:
                type: string
                description: Dimensões máximas da variação, no formato largura x altura.
                example: 135x135
              url:
                type: string
                format: uri
                description: URL pública da variação.
                example: https://cdn.example.com/products/2026/05/28/thumbnail_01JMZXZ72881MD2P37N2K97YJJ.webp
            required:
              - name
              - size
              - url
        in_use:
          type: boolean
          description: Indica se a imagem está associada a algum recurso.
          example: false
        reference_id:
          type: string
          nullable: true
          description: ID do recurso referenciado (se houver).
        reference_model:
          type: string
          nullable: true
          enum:
            - product
            - publication
            - store
          description: Tipo do recurso vinculado, em formato curto. Use o mesmo valor no filtro `filter[reference_model]=...`.
        created_at:
          type: string
          format: date-time
          description: Data de criação da imagem.
          example: "2026-05-28T10:00:00-03:00"
        updated_at:
          type: string
          format: date-time
          description: Data da última atualização da imagem.
          example: "2026-05-28T10:00:00-03:00"
      required:
        - id
        - original_source
        - urls
        - in_use
        - reference_id
        - reference_model
        - created_at
        - updated_at
    MediaCloneFromSkusResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message_code:
          type: string
          example: OK
        data:
          type: object
          properties:
            results:
              type: object
              description: Mapa key → lista de mídias clonadas. As keys são exatamente as enviadas nos targets.
              additionalProperties:
                type: array
                items:
                  "$ref": "#/components/schemas/ClonedMediaItem"
            ignored_skus:
              type: array
              description: SKUs que não pertencem (ou não estão associados) à loja autenticada. Não geram erro — as keys correspondentes voltam vazias.
              items:
                type: string
              example:
                - CAMISETA-VERM-M
          required:
            - results
            - ignored_skus
      required:
        - success
        - data
    ClonedMediaItem:
      type: object
      description: Mídia recém-clonada a partir de uma foto de produto. Nasce sem vínculo (`in_use=false`) — vincule ao anúncio normalmente via `images[].id`; se não for usada, a limpeza diária remove a cópia após ~72 horas.
      properties:
        id:
          type: string
          description: ID da nova mídia (26 caracteres). Use este valor nas `images` do anúncio/variação.
          example: 01JNB2T4G93QRT5V6W7X8Y9Z0A
        source_image_id:
          type: string
          description: ID da imagem de origem (foto da galeria do produto). Útil para rastrear de onde a cópia veio e evitar duplicar sugestões.
          example: 01JMZXZ72881MD2P37N2K97YJJ
        original_source:
          type: string
          format: uri
          description: URL da cópia em alta qualidade (WebP).
          example: https://cdn.example.com/products/2026/06/11/original_01JNB2T4G93QRT5V6W7X8Y9Z0A.webp
        urls:
          type: array
          description: "Variações de tamanho copiadas da imagem de origem (mesmos nomes do upload: `thumbnail`, `sm`, `md`, `lg`, `xl`)."
          items:
            type: object
            properties:
              name:
                type: string
                example: sm
              size:
                type: string
                nullable: true
                example: 200x200
              url:
                type: string
                format: uri
                example: https://cdn.example.com/products/2026/06/11/sm_01JNB2T4G93QRT5V6W7X8Y9Z0A.webp
            required:
              - name
              - url
      required:
        - id
        - source_image_id
        - original_source
        - urls
  responses:
    Unauthorized:
      description: Token não fornecido, inválido ou expirado
      content:
        "application/json":
          example:
            success: false
            code: 401
            message_code: UNAUTHORIZED
            description: A autenticação é necessária e falhou ou não foi fornecida.
            data: []
            errors:
              - O access_token da loja é obrigatório no cabeçalho Authorization
            meta: []
    Forbidden:
      description: Sem permissão para acessar este recurso
      content:
        "application/json":
          example:
            success: false
            code: 403
            message_code: FORBIDDEN
            description: Você não tem permissão para acessar este recurso.
            data: []
            errors:
              - "Você não tem permissão para acessar este recurso (escopos ausentes: store_products_write)"
            meta: []
    NotFound:
      description: Recurso não encontrado
      content:
        "application/json":
          example:
            success: false
            code: 404
            message_code: NOT_FOUND
            description: O recurso solicitado não foi encontrado.
            data: []
            errors:
              - Produto não encontrado.
            meta: []
    Duplicated:
      description: "Recurso duplicado (ex: SKU já existe nesta loja)"
      content:
        "application/json":
          example:
            success: false
            code: 409
            message_code: DUPLICATED
            description: Este SKU já está cadastrado para esta loja.
            data: []
            errors:
              - Este SKU já está cadastrado para esta loja.
            meta: []
    ValidationError:
      description: Erro de validação nos campos enviados
      content:
        "application/json":
          example:
            success: false
            code: 422
            message_code: VALIDATION_ERROR
            description: Foram encontrados erros de validação na requisição.
            data: []
            errors:
              sku:
                - O campo SKU é obrigatório.
              name:
                - O campo Nome é obrigatório.
              "dimensions.height":
                - O campo dimensions.height é obrigatório.
            meta: []
    Conflict:
      description: Endereco identico ja vinculado ao local de estoque
      content:
        "application/json":
          example:
            success: false
            message_code: CONFLICT
            data:
              message: Já existe um endereço idêntico vinculado ao local de estoque.
security:
  - integrationToken: []
