openapi: 3.1.0
info:
  title: API de Pedidos
  description: Avanço de status, emissão de NF-e / Declaração de Conteúdo e geração de etiquetas.
  version: 1.0.0
  contact:
    name: UniSupri
servers:
  - url: https://api.sandbox.samdevel.com.br
    description: Sandbox (ambiente de homologação)
tags:
  - name: Pedidos
    description: |-
      Encontrar pedidos, ler dashboards e **avançar o ciclo de vida**.
      
      Todo pedido tem um `workflow_type` (`standard`, `production`, `in_store_pickup`, `pre_order`, `backorder`, `collective`) que define quais transições de status são aceitas. **Existe uma única rota que muda estado:** [`POST /orders/{id}/status`](/reference/pedidos#tag/pedidos/POST/api/v1/sellers/orders/{id}/status). Cancelamento, conclusão de produção, retirada confirmada — tudo passa por aí. O que muda é o valor de `status` enviado.
      
      Você não precisa decorar o que pode chamar: [`GET /orders/{id}/possible-statuses`](/reference/pedidos#tag/pedidos/GET/api/v1/sellers/orders/{id}/possible-statuses) já devolve, para o estado atual do pedido, as transições válidas com `target_status` e `payload_schema` prontos. Renderize um botão por `next_action`, monte o `data` a partir do schema, mande na rota única.
      
      → Mapa completo do ciclo de vida em **[Pedidos — Visão geral](/guia/pedidos)**.
  - name: Fiscal
    description: |-
      Emissão e consulta de **NF-e** (modelo 55) e **Declaração de Conteúdo**.
      
      A plataforma não emite NF-e — ela é gerada no seu ERP, autorizada pela SEFAZ, e você registra a chave (e o XML) aqui para que o **DANFE** seja produzido em background. Para Declaração de Conteúdo é o inverso: a plataforma gera o PDF a partir dos dados do pedido, basta disparar.
      
      **Pré-condição:** o pedido precisa estar em `preparing` em diante (não em `paid`). Para Declaração também é preciso que a loja tenha a feature `fiscal_declaration` ativa — confira em [`GET /orders/{id}/fiscal`](/reference/pedidos#tag/fiscal/GET/api/v1/sellers/orders/{id}/fiscal) (`declaration_available`).
      
      Geração de PDF é **assíncrona**: dispara → polling em `/fiscal` até `has_pdf=true` → baixa via `/fiscal/{invoiceId}/pdf` (URL S3 válida por 15 min).
      
      → Passo a passo em **[Pedidos — Fiscal](/guia/pedidos-fiscal)**.
  - name: Etiquetas
    description: |-
      Geração e download de etiquetas (PDFs) dos shipments do pedido.
      
      Um pedido pode ter mais de um shipment (pacotes diferentes); cada shipment pode ter uma ou mais etiquetas (formatos diferentes). A geração é **assíncrona** — `POST /shipment-labels/generate` enfileira um job por shipment, e você faz polling em `GET /orders/{id}/shipments` até `labels_ready === labels_total`.
      
      Baixe cada etiqueta via `GET /logistics/shipments/{id}/labels/{labelId}/download` — devolve URL S3 assinada com 15 min de validade. Chamar `/generate` de novo **regenera** todas as etiquetas (não é incremental).
      
      → Modelo mental e cenários em **[Pedidos — Logística](/guia/pedidos-logistica)**.
  - name: Enums de Pedido
    description: |-
      **Tabelas de referência** dos tipos e valores do ecossistema de pedidos. Em vez de hardcodar listas de status, canais, métodos de pagamento ou entrega, consulte estas rotas — elas refletem exatamente os valores que a API aceita e devolve, já com `label` (pt-BR) e, quando aplicável, `color` para UI.
      
      A rota consolidada [`GET /orders/enums`](/reference/pedidos#tag/enums-de-pedido/GET/api/v1/sellers/orders/enums) traz **todos** os enums do pedido num só request. As rotas públicas de status (`/api/global/enums/order/status`) e de logística (`/api/logistics/enums/*`) completam o conjunto. Os valores só mudam em deploy.
      
      → Para as transições de status válidas a partir do estado atual de um pedido, use [`GET /orders/{id}/possible-statuses`](/reference/pedidos#tag/pedidos/GET/api/v1/sellers/orders/{id}/possible-statuses).
paths:
  "/api/v1/sellers/orders":
    get:
      tags:
        - Pedidos
      summary: Listar Pedidos
      description: |-
        Lista paginada de pedidos da loja autenticada. **É a rota que o painel chama no dia a dia para montar filas de trabalho** — pedidos pagos aguardando preparação, enviados aguardando entrega, etc.
        
        Combine `status` (aceita CSV: `paid,preparing`) com `date_from`/`date_to` para recortes operacionais. Para visão agregada por dia ou KPIs do dia, prefira `/dashboard` ou `/summary`. Para o payload completo de um pedido específico, use `/orders/{id}`.
        
        Paginação via `limit` (default 20); o `meta` da resposta carrega `current_page`, `last_page` e `total`.
        
        **Privacidade do comprador:** os dados de identificação do cliente só são liberados após a confirmação do pagamento. Enquanto `customer_data_released` for `false` (pedidos não-pagos), o campo `customer_name` é omitido. A flag passa a `true` a partir de `paid` e nos status operacionais seguintes. Pelo mesmo motivo, o parâmetro `search` por CPF/CNPJ ou nome do comprador só encontra pedidos já pagos — busca por `order_number` funciona em qualquer status.
      security:
        - bearer: []
      parameters:
        - name: page
          in: query
          required: false
          schema:
            type: integer
            example: 1
        - name: limit
          in: query
          required: false
          description: Tamanho da página (default 20)
          schema:
            type: integer
            example: 20
        - name: status
          in: query
          required: false
          description: "Filtra por status do pedido (ex: `paid`, `preparing`, `shipped`). Aceita múltiplos valores separados por vírgula."
          schema:
            type: string
        - name: search
          in: query
          required: false
          description: Busca por número do pedido ou nome do cliente
          schema:
            type: string
        - name: channel
          in: query
          required: false
          description: Canal de origem. Aceita múltiplos valores separados por vírgula.
          schema:
            type: string
            enum:
              - marketplace
              - website
              - direct
              - store_seller
              - physical_store
              - mobile_app
              - whatsapp
              - pos
              - api
        - name: type
          in: query
          required: false
          description: Tipo do pedido. Aceita múltiplos valores separados por vírgula.
          schema:
            type: string
            enum:
              - standard
              - production
              - pre_order
              - backorder
              - physical_store
        - name: workflow
          in: query
          required: false
          description: Filtra por `workflow_type`. Aceita múltiplos valores separados por vírgula.
          schema:
            type: string
            enum:
              - standard
              - production
              - in_store_pickup
              - pre_order
              - backorder
              - collective
        - name: delivery_method
          in: query
          required: false
          description: Filtra por método de entrega. Aceita múltiplos valores separados por vírgula.
          schema:
            type: string
            enum:
              - shipping
              - pickup
        - name: customer_id
          in: query
          required: false
          description: Pedidos de um cliente específico (ULID do cliente)
          schema:
            type: string
        - name: physical_store_id
          in: query
          required: false
          description: Pedidos vinculados a uma loja física
          schema:
            type: integer
        - name: agent_group_uid
          in: query
          required: false
          description: Filtra por grupo de agentes
          schema:
            type: string
        - name: item_id
          in: query
          required: false
          description: Pedidos contendo um item específico
          schema:
            type: integer
        - name: date_from
          in: query
          required: false
          description: Data inicial (ISO 8601)
          schema:
            type: string
            format: date-time
        - name: date_to
          in: query
          required: false
          description: Data final (ISO 8601)
          schema:
            type: string
            format: date-time
        - name: sort
          in: query
          required: false
          description: "Ordenação. Default `-created_at`. Permitido: `created_at`, `updated_at`, `total_order`, `status`. Prefixo `-` para descendente."
          schema:
            type: string
            example: "-created_at"
      responses:
        "200":
          description: Pedidos listados
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  - order_number: ORD-000123
                    checkout_group_id: 01K8PB1QABCDEFGHIJK
                    store_id: 01K8PB0KMM36AY2P0NKSZBP2NA
                    store_name: Minha Loja Premium
                    store:
                      id: 01K8PB0KMM36AY2P0NKSZBP2NA
                      name: Minha Loja Premium
                      website_domain: minhaloja.com.br
                    customer_id: 01K8PB2RCUST00001
                    customer_data_released: true
                    customer:
                      id: 01K8PB2RCUST00001
                      name: João Silva
                      email: joao@example.com
                    agent_group_uid: null
                    physical_store_id: null
                    type: standard
                    type_label: Padrão
                    channel: marketplace
                    channel_label: Marketplace
                    workflow_type: standard
                    workflow_type_label: Padrão
                    status: paid
                    status_label: Pago
                    status_color: green
                    totals:
                      products: 220
                      shipping: 29.9
                      discounts: -10
                      order: 239.9
                    items: []
                    items_count: 3
                    lines_count: 2
                    items_preview:
                      - title: Tênis Esportivo Azul
                        quantity: 2
                        thumbnail_url: https://cdn.example.com/produtos/tenis-azul-sm.webp
                    notes: null
                    metadata: null
                    delivery_method: shipping
                    delivery_method_label: Envio
                    picked_up_at: null
                    is_production_order: false
                    payment_method: pix
                    payment_method_label: PIX
                    payment_status: paid
                    payment_status_label: Pago
                    payment_expires_at: null
                    created_at: "2026-04-26T14:32:11Z"
                    updated_at: "2026-04-26T14:35:42Z"
                meta:
                  current_page: 1
                  last_page: 4
                  per_page: 20
                  total: 78
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/v1/sellers/orders/dashboard":
    get:
      tags:
        - Pedidos
      summary: Dashboard (período configurável)
      description: |-
        Estatísticas consolidadas dos últimos `days` dias (default 30, máx 365). Devolve quatro blocos:
        
        - `chart` — série temporal com pedidos vendidos, pendentes, cancelados e faturamento (`revenue`) por bucket (até 30 pontos no período).
        - `totals` — totais do período por categoria, incluindo `revenue` (GMV das vendas).
        - `totals_previous` — mesmos totais para o período anterior de igual duração (use para variação %).
        - `recent_orders` — últimos pedidos criados (limitado por `recent_limit`, default 10).
        
        Use para a tela "Visão geral" do seller. Para KPIs fixos do dia atual sem janela configurável, prefira `/summary`.
      security:
        - bearer: []
      parameters:
        - name: days
          in: query
          required: false
          description: Tamanho do período em dias (1-365). Default `30`.
          schema:
            type: integer
            minimum: 1
            maximum: 365
            default: 30
        - name: recent_limit
          in: query
          required: false
          description: Quantos pedidos recentes incluir na lista (1-50). Default `10`.
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
        - name: channel
          in: query
          required: false
          description: "Restringe o dashboard a um ou mais canais (separados por vírgula, ex: `website,store_seller`). Sem o parâmetro, considera todos os canais da loja."
          schema:
            type: string
            example: website,store_seller
      responses:
        "200":
          description: Dashboard carregado
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Dashboard carregado
                data:
                  chart:
                    - day: 27 abr
                      sold: 4
                      pending: 1
                      cancelled: 0
                      revenue: 1240.5
                    - day: 28 abr
                      sold: 6
                      pending: 2
                      cancelled: 1
                      revenue: 1893.4
                  recent_orders:
                    - id: ORD-000123
                      order_number: ORD-000123
                      customer_data_released: true
                      customer_name: João Silva
                      status: paid
                      status_label: Pago
                      status_color: green
                      workflow_type: standard
                      workflow_label: Padrão
                      total_order: 239.9
                      created_at: "2026-04-26T14:32:11Z"
                  totals:
                    sold: 142
                    pending: 18
                    awaiting_dispatch: 23
                    cancelled: 7
                    total: 190
                    revenue: 45230.8
                  totals_previous:
                    sold: 118
                    pending: 22
                    awaiting_dispatch: 19
                    cancelled: 9
                    total: 168
                    revenue: 38912.15
                  period:
                    days: 30
                    from: "2026-03-27T00:00:00Z"
                    to: "2026-04-26T23:59:59Z"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "403":
          "$ref": "#/components/responses/Forbidden"
  "/api/v1/sellers/orders/summary":
    get:
      tags:
        - Pedidos
      summary: Resumo do dia (KPIs fixos)
      description: |-
        KPIs do **dia de hoje** para o cabeçalho do painel: pedidos criados, receita, ticket médio, delta vs. ontem em %, contadores de pedidos em cada status operacional (`preparing`, `ready_to_ship`, `shipped`) e entregas concluídas hoje. Também desmembra pedidos abertos por canal.
        
        Não aceita filtros — sempre o panorama global da loja autenticada. Para janela configurável e gráfico de evolução, use `/dashboard`.
      security:
        - bearer: []
      responses:
        "200":
          description: Resumo obtido
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  today_count: 12
                  today_delta_pct: 33.3
                  today_revenue: 4587.5
                  today_avg_ticket: 382.29
                  awaiting_action: 4
                  preparing: 3
                  ready_to_ship: 2
                  shipped: 5
                  delivered_today: 7
                  by_channel:
                    site: 6
                    loja: 2
                    whatsapp: 3
                    direto: 1
                    vendedor_loja: 2
        "401":
          "$ref": "#/components/responses/Unauthorized"
  "/api/v1/sellers/orders/{id}":
    get:
      tags:
        - Pedidos
      summary: Detalhe do Pedido
      description: |-
        Payload completo de um pedido: itens com produto/publicação, cliente, snapshot de endereço, totais, splits financeiros resumidos, documentos fiscais (`invoices[]`), anotações internas, metadata de envio (carrier escolhido, opção de frete).
        
        É o que a tela de detalhe do pedido consome. Para apenas dados financeiros aprofundados (audit de comissão, benefícios aplicados), use `/financial`. Para apenas tracking, use `/tracking`.
        
        **Privacidade do comprador:** o objeto `customer`, o `delivery_address` e os snapshots de PII no `metadata` (`document_snapshot`, `phone_snapshot`, `address_snapshot`, ...) só são retornados após a confirmação do pagamento. Em pedidos não-pagos ou em análise de risco, `customer_data_released` vem `false` e esses campos são omitidos — o pedido pode ainda não se concretizar. A flag passa a `true` a partir de `paid`.
        
        **Link de pagamento (pedidos B2B):** em pedidos dos canais `direct` e `store_seller`, a resposta inclui `payment_url` (link público de pagamento) e `payment_link_target` (`platform` quando o link abre no frontend da plataforma; `store` quando abre no domínio da loja virtual). Ambos vêm `null` quando o pedido não está mais em `waiting_payment` ou o token expirou; nos demais canais os campos são omitidos. Enquanto o token é válido, `payment_token` também acompanha a resposta.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          description: Número do pedido (`order_number`)
          schema:
            type: string
            example: ORD-000123
      responses:
        "200":
          description: Pedido obtido
          content:
            "application/json":
              examples:
                com_cnpj:
                  summary: Transportadora com CNPJ (sem endereço fiscal)
                  value:
                    success: true
                    code: 200
                    message_code: SUCCESS
                    description: Requisicao realizada com sucesso.
                    data:
                      order_number: ORD-000123
                      checkout_group_id: 01K8PB1QABCDEFGHIJK
                      store_id: 01K8PB0KMM36AY2P0NKSZBP2NA
                      store:
                        id: 01K8PB0KMM36AY2P0NKSZBP2NA
                        name: Minha Loja Premium
                        logo_url: https://cdn.example.com/logo.webp
                        website_domain: minhaloja.com.br
                      customer_id: 01K8PB2RCUST00001
                      customer_data_released: true
                      customer:
                        id: 01K8PB2RCUST00001
                        name: João Silva
                        email: joao@example.com
                      sales_agent_uid: null
                      agent_group_uid: null
                      physical_store_id: null
                      type: standard
                      type_label: Padrão
                      channel: marketplace
                      channel_label: Marketplace
                      workflow_type: standard
                      workflow_type_label: Padrão
                      status: paid
                      status_label: Pago
                      status_color: green
                      totals:
                        products: 220
                        shipping: 29.9
                        discounts: -10
                        order: 239.9
                      items:
                        - id: 9981
                          item_id: ITM-0551
                          variation_id: null
                          product_id: 121
                          buybox_offer_uid: null
                          ad_type: single
                          quantity: 2
                          prices:
                            base_unit: 119.9
                            unit: 110
                            total_discount: 19.8
                            subtotal: 220
                          fees:
                            marketplace: 31.9
                          net_value: 188.1
                          publication:
                            id: ITM-0551
                            title: Tênis Esportivo Azul
                            thumbnail_url: https://cdn.example.com/produtos/tenis-azul-sm.webp
                          product:
                            id: 121
                            name: Tênis Esportivo Azul
                            sku: TEN-AZ-001
                            dimensions:
                              weight: 0.8
                              height: 12
                              width: 28
                              length: 35
                            thumbnail_url: https://cdn.example.com/produtos/tenis-azul-sm.webp
                          shipment_id: 4421
                          stock_origin: null
                          created_at: "2026-04-26T14:32:11Z"
                      applied_benefits:
                        - id: 871
                          order_item_id: 9981
                          benefit_type: discount
                          amount: -10
                          source_type: coupon
                          source_id: 23
                          beneficiary: customer
                          absorbed_by: marketplace
                          description: Cupom BEMVINDO10
                          snapshot:
                            code: BEMVINDO10
                            rule: first_purchase
                          created_at: "2026-04-26T14:32:11Z"
                      items_count: 2
                      lines_count: 1
                      items_preview:
                        - title: Tênis Esportivo Azul
                          quantity: 2
                          thumbnail_url: https://cdn.example.com/produtos/tenis-azul-sm.webp
                      invoices:
                        - id: 5b4f...
                          type: nfe
                          status: completed
                          invoice_key: "35260411222333000144550010000012341123456789"
                          invoice_number: "1234"
                          invoice_value: 239.9
                          pdf_url: null
                          created_at: "2026-04-26T15:01:22Z"
                      notes: null
                      shipping:
                        shipment_option_id: opt_001
                        carrier_id: 7
                        service_id: 3
                        carrier_name: Correios PAC
                        display_name: Correios PAC
                        delivery_time_hours: 72
                        carrier_fiscal:
                          carrier_id: 12
                          carrier_uid: 01K8CARRIER000CORREIOS
                          name: Correios PAC
                          operates_with_cnpj: true
                          legal_name: Empresa Brasileira de Correios e Telégrafos
                          document:
                            type: cnpj
                            number: "34028316000103"
                            formatted: 34.028.316/0001-03
                          state_registration: null
                          billing_address: null
                      delivery_method: shipping
                      delivery_method_label: Envio
                      picked_up_at: null
                      is_production_order: false
                      payment_method: pix
                      payment_method_label: PIX
                      payment_expires_at: null
                      created_at: "2026-04-26T14:32:11Z"
                      updated_at: "2026-04-26T14:35:42Z"
                sem_cnpj:
                  summary: Transportadora sem CNPJ (carrier_fiscal nulo)
                  value:
                    success: true
                    code: 200
                    message_code: SUCCESS
                    description: Requisicao realizada com sucesso.
                    data:
                      order_number: ORD-000124
                      checkout_group_id: 01K8PB1QXYZ000124
                      store_id: 01K8PB0KMM36AY2P0NKSZBP2NA
                      store:
                        id: 01K8PB0KMM36AY2P0NKSZBP2NA
                        name: Minha Loja Premium
                        logo_url: https://cdn.example.com/logo.webp
                        website_domain: minhaloja.com.br
                      customer_id: 01K8PB2RCUST00002
                      customer:
                        id: 01K8PB2RCUST00002
                        name: Maria Souza
                        email: maria@example.com
                      status: paid
                      status_label: Pago
                      totals:
                        products: 80
                        shipping: 15
                        discounts: 0
                        order: 95
                      items: []
                      shipping:
                        shipment_option_id: opt_777
                        carrier_id: 99
                        service_id: 1
                        carrier_name: Transportadora Local (MEI)
                        display_name: Entrega econômica
                        delivery_time_hours: 120
                        carrier_fiscal: null
                      delivery_method: shipping
                      delivery_method_label: Envio
                      created_at: "2026-04-27T09:00:00Z"
                      updated_at: "2026-04-27T09:00:00Z"
                com_cnpj_e_endereco:
                  summary: Transportadora com CNPJ e endereço fiscal
                  value:
                    success: true
                    code: 200
                    message_code: SUCCESS
                    description: Requisicao realizada com sucesso.
                    data:
                      order_number: ORD-000125
                      checkout_group_id: 01K8PB1QXYZ000125
                      store_id: 01K8PB0KMM36AY2P0NKSZBP2NA
                      store:
                        id: 01K8PB0KMM36AY2P0NKSZBP2NA
                        name: Minha Loja Premium
                        logo_url: https://cdn.example.com/logo.webp
                        website_domain: minhaloja.com.br
                      customer_id: 01K8PB2RCUST00003
                      customer:
                        id: 01K8PB2RCUST00003
                        name: Carlos Lima
                        email: carlos@example.com
                      status: preparing
                      status_label: Em preparação
                      totals:
                        products: 220
                        shipping: 29.9
                        discounts: -10
                        order: 239.9
                      items: []
                      shipping:
                        shipment_option_id: opt_001
                        carrier_id: 12
                        service_id: 3
                        carrier_name: Correios PAC
                        display_name: Correios PAC
                        delivery_time_hours: 72
                        carrier_fiscal:
                          carrier_id: 12
                          carrier_uid: 01K8CARRIER000CORREIOS
                          name: Correios PAC
                          operates_with_cnpj: true
                          legal_name: Empresa Brasileira de Correios e Telégrafos
                          document:
                            type: cnpj
                            number: "34028316000103"
                            formatted: 34.028.316/0001-03
                          state_registration: null
                          billing_address:
                            uid: 01K8CARRIERADDR0001
                            label: Matriz
                            recipient: Correios
                            address: SBN Quadra 1, Bloco A
                            number: S/N
                            complement: Edifício Sede
                            district: Asa Norte
                            city: Brasília
                            state: DF
                            zip_code: "70002900"
                            country: BRA
                            latitude: -15.7934
                            longitude: -47.8822
                            place_id: null
                      delivery_method: shipping
                      delivery_method_label: Envio
                      created_at: "2026-04-27T10:00:00Z"
                      updated_at: "2026-04-27T10:05:00Z"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/possible-statuses":
    get:
      tags:
        - Pedidos
      summary: Próximos Passos Válidos
      description: |-
        **Esta é a rota que você deve chamar antes de qualquer mudança de status.** Para o estado atual do pedido, devolve as transições aceitáveis com tudo que o integrador precisa para chamar a rota única `/status`:
        
        | Campo | Para que serve |
        |---|---|
        | `action` | Slug semântico (`mark-preparing`, `cancel`, `start-production`). Útil para analytics ou para mapear ícone/botão. |
        | `target_status` | O valor a enviar em `status` na rota única. |
        | `label` | Texto pronto para botão da UI (já em pt-BR). |
        | `payload_schema` | JSONSchema do `data` aceito. `null` quando a transição não exige payload. |
        
        Padrão de uso: renderize um botão por `next_action`, monte `data` a partir do `payload_schema` (quando houver), envie em [`POST /orders/{id}/status`](/reference/pedidos#tag/pedidos/POST/api/v1/sellers/orders/{id}/status). Se você sempre passa por aqui antes de mudar status, é impossível mandar uma transição inválida.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      responses:
        "200":
          description: Transições válidas
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  current_status: paid
                  workflow_type: standard
                  next_actions:
                    - action: mark-preparing
                      target_status: preparing
                      label: Iniciar preparação
                      payload_schema: null
                    - action: cancel
                      target_status: cancelled
                      label: Cancelar pedido
                      payload_schema:
                        type: object
                        properties:
                          reason:
                            type: string
                            maxLength: 500
                            description: Motivo (opcional, registrado no histórico)
                  possible_transitions:
                    - preparing
                    - cancelled
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/events":
    get:
      tags:
        - Pedidos
      summary: Histórico Granular de Eventos
      description: |-
        Linha do tempo completa do pedido. Cada mudança de status, registro fiscal, anotação interna ou ação de operador vira um evento com autor, descrição e metadata. Use para timeline detalhada, auditoria ou SAC.
        
        Para a versão consolidada de **rastreio de entrega** (apenas tracking_code, datas-chave), prefira `/tracking` — é uma visão simplificada do mesmo dado.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      responses:
        "200":
          description: Eventos listados
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  - id: 4501
                    event_type: status_changed
                    event_label: Status alterado
                    author_type: seller
                    author_label: Seller
                    author_id: 87
                    author_name: João Operador
                    description: Pedido movido de paid para preparing.
                    metadata:
                      from: paid
                      to: preparing
                    created_at: "2026-04-26T15:01:22Z"
                  - id: 4502
                    event_type: invoice_issued
                    event_label: Nota fiscal emitida
                    author_type: seller
                    author_label: Seller
                    author_id: 87
                    author_name: João Operador
                    description: NF-e 1234 registrada e DANFE em geração.
                    metadata:
                      invoice_id: 5b4f...
                      invoice_number: "1234"
                    created_at: "2026-04-26T15:10:00Z"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/notes":
    put:
      tags:
        - Pedidos
      summary: Atualizar Anotações Internas
      description: |-
        Texto livre da loja sobre o pedido — **não é visível ao cliente**. Use para lembretes operacionais ("ligar antes de despachar", "embalagem para presente", "cliente vai retirar quarta").
        
        É um PUT puro: você envia o texto inteiro a cada chamada (não é append/diff) ou `null` para limpar. Não há limite de chamadas — registre quantas vezes precisar.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              properties:
                notes:
                  type: string
                  nullable: true
                  maxLength: 2000
                  description: Texto da anotação interna. Envie `null` para limpar.
            example:
              notes: Cliente solicitou embalagem para presente.
      responses:
        "200":
          description: Anotações atualizadas — devolve o pedido completo atualizado em `data`
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/v1/sellers/orders/{id}/financial":
    get:
      tags:
        - Pedidos
      summary: Detalhamento Financeiro
      description: |-
        Visão financeira aprofundada do pedido: **quem recebe quanto** (splits de receita entre seller, marketplace e sales agent), audit de comissão por item com taxa e valor líquido, e benefícios aplicados (cupons, descontos, regras absorvidas pelo marketplace).
        
        Use para tela de "extrato do pedido" ou conferência de repasse esperado. Para totais simplificados do pedido (sem splits), os campos `totals` no `/orders/{id}` já são suficientes.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      responses:
        "200":
          description: Dados financeiros obtidos
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  order_number: ORD-000123
                  checkout_group_id: 01K8PB1QABCDEFGHIJK
                  store_id: 01K8PB0KMM36AY2P0NKSZBP2NA
                  totals:
                    products: 220
                    shipping: 29.9
                    discounts: -10
                    order: 239.9
                  paid: 239.9
                  splits:
                    - id: 01K8SPLIT00000SELLER
                      order_id: 01K8PB1QORDER0005501
                      recipient: seller
                      recipient_label: Loja
                      beneficiary_id: 01K8PB0KMM36AY2P0NKSZBP2NA
                      beneficiary_name: Minha Loja Premium
                      type: items_net_value
                      type_label: Valor líquido dos itens
                      description: Repasse ao seller após comissão e descontos
                      amount: 195.1
                      created_at: "2026-04-26T14:35:42Z"
                    - id: 01K8SPLIT0000MKTPLACE
                      order_id: 01K8PB1QORDER0005501
                      recipient: platform
                      recipient_label: Marketplace
                      beneficiary_id: null
                      beneficiary_name: Plataforma
                      type: commission
                      type_label: Comissão
                      description: Comissão padrão
                      amount: 34.8
                      created_at: "2026-04-26T14:35:42Z"
                  audit_commissions:
                    - id: 991
                      order_item_id: 9981
                      commission_rate: 14.5
                      commission_value: 31.9
                      absorbed_discount: 0
                      net_value: 188.1
                      created_at: "2026-04-26T14:32:11Z"
                      updated_at: "2026-04-26T14:35:42Z"
                  applied_benefits:
                    - id: 871
                      order_item_id: 9981
                      benefit_type: discount
                      amount: -10
                      source_type: coupon
                      source_id: 23
                      beneficiary: customer
                      absorbed_by: marketplace
                      description: Cupom BEMVINDO10
                      snapshot:
                        code: BEMVINDO10
                        rule: first_purchase
                      created_at: "2026-04-26T14:32:11Z"
                  created_at: "2026-04-26T14:32:11Z"
                  updated_at: "2026-04-26T14:35:42Z"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/tracking":
    get:
      tags:
        - Pedidos
      summary: Rastreio Consolidado
      description: |-
        "Onde está meu pedido" — view simples de acompanhamento. Devolve status atual, `tracking_code`, `tracking_url` pública (quando o transportador fornece), `estimated_delivery_at`, `delivered_at` e `picked_up_at` (em retiradas).
        
        É a rota certa para uma tela de acompanhamento ao cliente final. Para o histórico granular (toda mudança de estado com autor e metadata), use [`/events`](/reference/pedidos#tag/pedidos/GET/api/v1/sellers/orders/{id}/events).
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      responses:
        "200":
          description: Tracking obtido
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  order_number: ORD-000123
                  checkout_group_id: 01K8PB1QABCDEFGHIJK
                  store_id: 01K8PB0KMM36AY2P0NKSZBP2NA
                  customer_id: 01K8PB2RCUST00001
                  status: shipped
                  status_label: Enviado
                  tracking_code: BR123456789BR
                  tracking_url: https://rastreio.exemplo.com/BR123456789BR
                  estimated_delivery_at: "2026-05-02T00:00:00Z"
                  delivered_at: null
                  picked_up_at: null
                  workflow_info:
                    type: standard
                    type_label: Padrão
                  created_at: "2026-04-26T14:32:11Z"
                  updated_at: "2026-04-28T09:15:00Z"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/status":
    post:
      tags:
        - Pedidos
      summary: Avançar Status (rota única)
      description: |-
        **Toda mudança de estado de um pedido passa por aqui** — iniciar preparação, marcar enviado, confirmar retirada, concluir produção, cancelar. O integrador não precisa mapear rota por workflow.
        
        **Padrão de uso correto:**
        
        1. Chame [`GET /orders/{id}/possible-statuses`](/reference/pedidos#tag/pedidos/GET/api/v1/sellers/orders/{id}/possible-statuses).
        2. Escolha uma das `next_actions` retornadas.
        3. Envie aqui `{ "status": <target_status>, "data": <payload conforme payload_schema> }`.
        
        **Quando dá errado:**
        
        - **`422` com `errors.status`** — a transição não é permitida a partir do estado atual ("Transição inválida: não é possível ir de X para Y"). Geralmente significa que o pedido avançou (concorrência) ou que o cache de `possible-statuses` está velho. Refaça `/possible-statuses`.
        - **`422` com `errors` por campo** — payload em `data` faltando ou divergindo do `payload_schema` (ex.: `confirmation_code` ausente em `picked_up`).
        - **`404`** — `order_number` inexistente ou de outra loja.
        
        > Cancelamento é uma transição como qualquer outra: `status=cancelled` (com `data.reason` opcional). Não procure por uma rota só de cancelar — ela não existe de propósito; tudo passa por aqui. **Atenção:** o seller só consegue cancelar enquanto o pedido não entrou em preparação/produção; a partir de `preparing`, `production_started`, `ready_to_ship` etc., o cancelamento é restrito à operação da plataforma.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              required:
                - status
              properties:
                status:
                  type: string
                  description: Status alvo. Use o `target_status` devolvido por `possible-statuses`.
                  enum:
                    - preparing
                    - ready_to_ship
                    - shipped
                    - delivered
                    - cancelled
                    - production_started
                    - awaiting_materials
                    - production_in_progress
                    - production_finished
                    - reserved
                    - ready_for_pickup
                    - picked_up
                    - pickup_expired
                    - available
                    - restocked
                data:
                  type: object
                  description: |-
                    Payload específico da transição. Forma definida por `payload_schema` em `possible-statuses`. Omitir quando `payload_schema=null`.
                    
                    | status | data |
                    |---|---|
                    | `shipped` | `{ tracking_code?: string (max 100) }` |
                    | `cancelled` | `{ reason?: string (max 500) }` |
                    | `production_started` | `{ estimated_days?: integer }` |
                    | `awaiting_materials` | `{ materials?: array }` |
                    | `picked_up` | `{ confirmation_code: string }` (**obrigatório**) |
                    | demais | sem `data` |
                  additionalProperties: true
                  properties:
                    tracking_code:
                      type: string
                      maxLength: 100
                      description: Para `status=shipped`. Opcional.
                    reason:
                      type: string
                      maxLength: 500
                      description: Para `status=cancelled`. Opcional.
                    estimated_days:
                      type: integer
                      minimum: 1
                      description: Para `status=production_started`. Opcional.
                    materials:
                      type: array
                      items:
                        type: string
                      description: Para `status=awaiting_materials`. Opcional.
                    confirmation_code:
                      type: string
                      maxLength: 50
                      description: Para `status=picked_up`. **Obrigatório** nessa transição.
            examples:
              iniciar_preparacao:
                summary: Iniciar preparação (sem payload)
                value:
                  status: preparing
              marcar_enviado_com_rastreio:
                summary: Marcar enviado com tracking
                value:
                  status: shipped
                  data:
                    tracking_code: BR123456789BR
              iniciar_producao:
                summary: Iniciar produção (workflow=production)
                value:
                  status: production_started
                  data:
                    estimated_days: 7
              aguardando_materiais:
                summary: Aguardando materiais (workflow=production)
                value:
                  status: awaiting_materials
                  data:
                    materials:
                      - Tecido azul
                      - Zíper 20cm
              confirmar_retirada:
                summary: Confirmar retirada (workflow=in_store_pickup)
                value:
                  status: picked_up
                  data:
                    confirmation_code: A1B2C3
              cancelar:
                summary: Cancelar com motivo
                value:
                  status: cancelled
                  data:
                    reason: Cliente solicitou cancelamento por arrependimento.
      responses:
        "200":
          description: Transição realizada — devolve o pedido atualizado (versão condensada, sem relações carregadas) em `data`
          content:
            "application/json":
              example:
                data:
                  order_number: ORD-000123
                  checkout_group_id: 01K8PB1QABCDEFGHIJK
                  customer_id: 01K8PB2RCUST00001
                  customer_data_released: true
                  agent_group_uid: null
                  physical_store_id: null
                  type: standard
                  type_label: Padrão
                  channel: marketplace
                  channel_label: Marketplace
                  workflow_type: standard
                  workflow_type_label: Padrão
                  status: preparing
                  status_label: Preparando
                  status_color: blue
                  cancellation_message: null
                  risk_analysis: null
                  totals:
                    products: 220
                    shipping: 29.9
                    discounts: -10
                    order: 239.9
                  notes: null
                  metadata: null
                  delivery_method: shipping
                  delivery_method_label: Envio
                  picked_up_at: null
                  is_production_order: false
                  payment_expires_at: null
                  created_at: "2026-04-26T14:32:11Z"
                  updated_at: "2026-04-27T14:32:11Z"
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          description: Transição inválida ou payload incorreto
          content:
            "application/json":
              examples:
                transicao_invalida:
                  summary: Status alvo não disponível para o estado/workflow atual
                  value:
                    success: false
                    code: 422
                    message_code: VALIDATION_ERROR
                    description: Foram encontrados erros de validacao na requisicao.
                    data: []
                    errors:
                      status:
                        - "Transição inválida: não é possível ir de \"Pago\" para \"Enviado\""
                payload_invalido:
                  summary: Payload faltando ou inválido
                  value:
                    success: false
                    code: 422
                    message_code: VALIDATION_ERROR
                    description: Foram encontrados erros de validacao na requisicao.
                    data: []
                    errors:
                      confirmation_code:
                        - O campo confirmation_code é obrigatório.
  "/api/v1/sellers/orders/{id}/fiscal":
    get:
      tags:
        - Fiscal
      summary: Documentos Fiscais do Pedido
      description: |-
        **Primeira chamada do fluxo fiscal.** Devolve:
        
        - `invoices[]` — documentos já emitidos para o pedido (vazio na primeira vez). Cada item traz `id`, `type` (`nfe` ou `declaration`), `status` e `has_pdf` — use `has_pdf` para saber se o PDF já está pronto para download.
        - `declaration_available` — se a sua loja tem a feature `fiscal_declaration` ativa. Se vier `false`, só resta NF-e.
        
        Também é a rota de **polling** depois que você dispara emissão de Declaração (`POST /fiscal/declaration`) ou registra NF-e com XML (`POST /fiscal/nfe/key`) — chame em loop curto até o `has_pdf` virar `true`, então baixe via `/fiscal/{invoiceId}/pdf`.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      responses:
        "200":
          description: Documentos listados
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Documentos fiscais listados
                data:
                  invoices:
                    - id: 5b4f...
                      type: nfe
                      status: completed
                      error_message: null
                      has_pdf: true
                      invoice_key: "35260411222333000144550010000012341123456789"
                      invoice_number: "1234"
                      invoice_value: 249.9
                      created_at: "2026-04-26T15:10:00Z"
                  declaration_available: true
        "401":
          "$ref": "#/components/responses/Unauthorized"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/fiscal/declaration":
    post:
      tags:
        - Fiscal
      summary: Emitir Declaração de Conteúdo
      description: |-
        **Para lojas que não emitem NF-e** (típico em MEI ou PF de baixo volume). A plataforma gera o PDF a partir dos dados do pedido — você só dispara.
        
        A geração é **assíncrona** (`202 Accepted`). Depois disso é polling em [`GET /orders/{id}/fiscal`](/reference/pedidos#tag/fiscal/GET/api/v1/sellers/orders/{id}/fiscal) até o invoice ficar com `has_pdf=true`, então download em `/fiscal/{invoiceId}/pdf`.
        
        **Pré-condições:**
        
        - Pedido em status `preparing` em diante (não pode ser `paid`). Tentar em `paid` retorna 422.
        - Loja com a feature `fiscal_declaration` ativa (`declaration_available=true` em `/fiscal`). Sem a feature, retorna 403.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      responses:
        "202":
          description: Geração enfileirada
          content:
            "application/json":
              example:
                success: true
                code: 202
                message_code: SUCCESS
                description: Declaração de conteúdo solicitada. PDF sendo gerado
                data:
                  invoice:
                    id: 8c7e...
                    type: declaration
                    status: pending
                    error_message: null
                    has_pdf: false
                    invoice_key: null
                    invoice_number: null
                    invoice_value: null
                    created_at: "2026-04-26T15:10:00Z"
        "403":
          "$ref": "#/components/responses/Forbidden"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/v1/sellers/orders/{id}/fiscal/nfe/key":
    post:
      tags:
        - Fiscal
      summary: Registrar NF-e (chave + XML)
      description: |-
        **Caminho preferido quando você emite NF-e no seu ERP e tem o XML em mãos.** Registra a chave de acesso e o XML autorizado de uma só vez. A partir do XML, a plataforma gera o **DANFE** (PDF) em background — esse é o documento que vai junto com a mercadoria.
        
        Resposta `201 Created`. O DANFE entra na fila e tipicamente fica pronto em alguns segundos — siga o fluxo de polling em [`GET /orders/{id}/fiscal`](/reference/pedidos#tag/fiscal/GET/api/v1/sellers/orders/{id}/fiscal).
        
        **Quando esta rota não é o caminho certo:**
        
        - Se você tem **XML em arquivo separado** sem registrar a chave: use [`POST /orders/{id}/invoice/upload-xml`](/reference/pedidos#tag/fiscal/POST/api/v1/sellers/orders/{id}/invoice/upload-xml) — upload `multipart` que extrai a chave do próprio XML.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              required:
                - type
                - invoice_key
                - invoice_xml
              properties:
                type:
                  type: string
                  enum:
                    - nfe
                  description: Tipo do documento. Atualmente sempre `nfe` nesta rota.
                invoice_key:
                  type: string
                  minLength: 44
                  maxLength: 44
                  description: Chave de acesso da NF-e (44 dígitos).
                invoice_number:
                  type: string
                  nullable: true
                  description: Número da NF-e (opcional).
                invoice_value:
                  type: number
                  nullable: true
                  description: Valor total da nota (opcional).
                invoice_xml:
                  type: string
                  description: XML autorizado da NF-e. **Obrigatório** — usado para gerar o DANFE.
            example:
              type: nfe
              invoice_key: "35260411222333000144550010000012341123456789"
              invoice_number: "1234"
              invoice_value: 249.9
              invoice_xml: <?xml version="1.0"?>...<nfeProc>...</nfeProc>
      responses:
        "201":
          description: NF-e registrada
          content:
            "application/json":
              example:
                success: true
                code: 201
                message_code: SUCCESS
                description: NF-e registrada. DANFE sendo gerado
                data:
                  invoice:
                    id: 5b4f...
                    type: nfe
                    status: pending
                    error_message: null
                    has_pdf: false
                    invoice_key: "35260411222333000144550010000012341123456789"
                    invoice_number: "1234"
                    invoice_value: 249.9
                    created_at: "2026-04-26T15:10:00Z"
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/v1/sellers/orders/{id}/invoice/upload-xml":
    post:
      tags:
        - Fiscal
      summary: Upload Manual de XML
      description: |-
        **Use quando você tem o arquivo .xml em mãos** mas a chave ainda não foi registrada na plataforma. Cenário típico: XML salvo do email do contador, exportado de outro sistema, ou recuperado de backup.
        
        Envio em `multipart/form-data` com campo `xml` contendo o arquivo. A chave de acesso é **extraída automaticamente do próprio XML** (atributo `Id="NFe..."` em `infNFe`) e validada por mod-11 — você não precisa enviar a chave separada.
        
        O XML é persistido, o `OrderInvoice` entra em `processing` e o DANFE é gerado em background. Mesmo fluxo de polling de [`GET /orders/{id}/fiscal`](/reference/pedidos#tag/fiscal/GET/api/v1/sellers/orders/{id}/fiscal).
        
        **Quando falha:**
        
        - **`422`** — XML sem chave válida, mod-11 inválido, arquivo vazio, extensão diferente de `.xml`, ou >1 MB.
        - **`409 chave_already_used`** — essa chave de NF-e já está vinculada a outro pedido (geralmente erro humano: arquivo do pedido errado).
        - **`409 invoice_already_validated`** — o invoice deste pedido já foi validado; reabra antes de reenviar.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          description: Número do pedido (`order_number`).
          schema:
            type: string
            example: ORD-000123
      requestBody:
        required: true
        content:
          "multipart/form-data":
            schema:
              type: object
              required:
                - xml
              properties:
                xml:
                  type: string
                  format: binary
                  description: "Arquivo XML autorizado da NF-e. Extensão `.xml` obrigatória. Tamanho máximo: 1 MB."
      responses:
        "200":
          description: XML aceito e persistido
          content:
            "application/json":
              example:
                order_invoice_id: 5b4f...
                provider: upload
                chave: "35260411222333000144550010000012341123456789"
                xml_url: https://s3.amazonaws.com/.../35260411222333000144550010000012341123456789.xml?X-Amz-Signature=...
                xml_url_expires_at: "2026-04-26T15:25:00Z"
        "409":
          description: Conflito — chave já vinculada a outro pedido ou invoice já validado
          content:
            "application/json":
              examples:
                chave_duplicada:
                  summary: Chave já vinculada a outro pedido
                  value:
                    error: chave_already_used
                    message: Esta NF-e já está vinculada a outro pedido.
                invoice_validado:
                  summary: OrderInvoice já validado
                  value:
                    error: invoice_already_validated
                    message: O OrderInvoice deste pedido já está validado/completo. Refaça o invoice antes de reenviar XML.
        "422":
          "$ref": "#/components/responses/ValidationError"
  "/api/v1/sellers/orders/{id}/fiscal/{invoiceId}/pdf":
    get:
      tags:
        - Fiscal
      summary: Baixar PDF (DANFE ou Declaração)
      description: |-
        Mesma rota para os dois tipos de documento — o `filename` da resposta já vem com o prefixo certo (`danfe_` ou `declaracao_`).
        
        Devolve uma URL S3 assinada **válida por 15 minutos**. Não armazene a URL — se expirar, chame esta rota de novo para obter uma nova. `{invoiceId}` é o `id` que veio em `invoices[]` na resposta de `/fiscal`.
        
        Quando o PDF ainda não terminou de ser gerado, retorna **`202 Accepted`** com `status=pending` — não é erro, é sinal de "tente de novo". Volte para o polling em `/fiscal` até `has_pdf=true` e tente baixar de novo.
        
        > Quando o consumidor é gateway/proxy que prefere JSON, devolve `{ url, filename, expires_in }`. Em acesso direto sem proxy, segue redirect direto pro S3.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
        - name: invoiceId
          in: path
          required: true
          schema:
            type: string
            example: 5b4f...
      responses:
        "200":
          description: URL do PDF gerada
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: URL do PDF gerada
                data:
                  url: https://s3.amazonaws.com/.../danfe_ORD-000123.pdf?X-Amz-Signature=...
                  filename: danfe_ORD-000123.pdf
                  expires_in: 15 minutos
        "202":
          description: PDF ainda sendo gerado
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/fiscal/{invoiceId}/view":
    get:
      tags:
        - Fiscal
      summary: Dados Completos do Documento (sem PDF)
      description: |-
        Devolve **todos os atributos persistidos** do invoice — chave, número, valor, status, tipo, metadata da declaração, timestamps. Útil para uma tela de "detalhe fiscal" no painel ou para conferência rápida sem precisar baixar o PDF.
        
        Para o PDF em si, use [`/fiscal/{invoiceId}/pdf`](/reference/pedidos#tag/fiscal/GET/api/v1/sellers/orders/{id}/fiscal/{invoiceId}/pdf).
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
        - name: invoiceId
          in: path
          required: true
          schema:
            type: string
            example: 5b4f...
      responses:
        "200":
          description: Documento obtido
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/shipments":
    get:
      tags:
        - Etiquetas
      summary: Shipments e Etiquetas do Pedido
      description: |-
        Lista os **pacotes físicos** do pedido com suas etiquetas embutidas. Um pedido pode ter um ou vários shipments; cada shipment pode ter uma ou várias etiquetas (formatos diferentes).
        
        **É a rota de polling depois de disparar geração de etiquetas** (`POST /shipment-labels/generate`). Consulte em loop até `labels_ready === labels_total` em cada shipment — daí passe para download via `/logistics/shipments/{id}/labels/{labelId}/download` usando os IDs daqui.
        
        A resposta também traz `tracking_code`, `carrier`, dimensões dos volumes e o flag `label_generation_blocked` — útil para a tela de detalhe logístico.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      responses:
        "200":
          description: Shipments listados
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Shipments do pedido listados
                data:
                  shipments:
                    - id: 4421
                      uid: shp_a1b2c3
                      type: sales_order
                      status: ready_to_ship
                      status_label: Pronto para Envio
                      delivery_method: third_party
                      is_pickup: false
                      is_free_shipping: false
                      tracking_code: BR123456789BR
                      external_id: null
                      invoice_number: "1234"
                      freight_cost: 29.9
                      weight: 1.6
                      volumes_count: 1
                      label_generation_blocked: false
                      label_url: null
                      carrier:
                        id: 12
                        name: Correios
                      volumes:
                        - volume_index: 1
                          width: 28
                          height: 12
                          length: 35
                          physical_weight: 1.6
                          chargeable_weight: 1.6
                      labels:
                        - id: lbl_xyz
                          format: a4
                          format_label: A4 (PDF)
                          source: platform
                          source_label: Plataforma
                          status: completed
                          status_label: Disponível
                          is_ready: true
                          completed_at: "2026-04-26T16:02:00Z"
                          expires_at: null
                      labels_ready: 1
                      labels_total: 1
                      created_at: "2026-04-26T14:35:42Z"
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/v1/sellers/orders/{id}/shipment-labels/generate":
    post:
      tags:
        - Etiquetas
      summary: (Re)gerar Etiquetas dos Shipments
      description: |-
        Enfileira **um job por shipment** do pedido para gerar as etiquetas. Operação **assíncrona** — retorna `202 Accepted` com a lista de shipments efetivamente enfileirados.
        
        **Chamar de novo regenera tudo.** Não é incremental: uma chamada apaga etiquetas anteriores e dispara jobs novos para todos os shipments não-bloqueados. Use com consciência — se 1 de 3 deu errado, regerar afeta os outros 2 também.
        
        **Shipments pulados:** os com `label_generation_blocked=true` não entram em `queued_shipments`. O `total` pode ser menor que o número real de shipments. Esse flag fica em `true` quando o sistema sabe que há um problema impossível de resolver automaticamente (endereço inválido, conta do transportador suspensa) — caso de operação.
        
        Depois desta chamada, faça polling em [`/orders/{id}/shipments`](/reference/pedidos#tag/etiquetas/GET/api/v1/sellers/orders/{id}/shipments).
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            example: ORD-000123
      responses:
        "202":
          description: Geração enfileirada
          content:
            "application/json":
              example:
                success: true
                code: 202
                message_code: SUCCESS
                description: Etiquetas redefinidas. Geração em andamento.
                data:
                  queued_shipments:
                    - 4421
                  total: 1
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/seller/logistics/shipments/{id}/labels":
    get:
      tags:
        - Etiquetas
      summary: Listar Etiquetas de um Shipment
      description: |-
        Devolve apenas o array de etiquetas de um shipment específico — mesma informação que vem em `shipments[].labels` em `/orders/{id}/shipments`, mas servida isolada.
        
        Use na tela "detalhe do shipment", quando você já tem o `shipment.id` e não quer recarregar todos os shipments do pedido só para conferir as etiquetas.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          description: ID numérico do shipment
          schema:
            type: integer
            example: 4421
      responses:
        "200":
          description: Etiquetas listadas
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  shipment_id: 4421
                  labels:
                    - id: lbl_xyz
                      format: a4
                      format_label: A4 (PDF)
                      source: platform
                      source_label: Plataforma
                      status: completed
                      status_label: Disponível
                      is_ready: true
                      completed_at: "2026-04-26T16:02:00Z"
                  formats_pending: []
        "404":
          "$ref": "#/components/responses/NotFound"
  "/api/seller/logistics/shipments/{id}/labels/{labelId}/download":
    get:
      tags:
        - Etiquetas
      summary: Baixar PDF da Etiqueta
      description: |-
        Devolve URL S3 assinada **válida por 15 minutos** para o PDF da etiqueta. Não armazene a URL — se expirar, chame esta rota de novo.
        
        `{id}` é o `shipment.id` (numérico); `{labelId}` é o `label.id` (vem em `shipments[].labels[].id`).
        
        Se a etiqueta ainda não terminou de ser gerada (`is_ready=false`), retorna **`422 UNPROCESSABLE_ENTITY`** com mensagem `Etiqueta ainda não disponível`. Volte para o polling em `/orders/{id}/shipments` antes de tentar de novo.
        
        > Em telas de impressão em massa, gere as URLs sob demanda (no clique em "Imprimir"), não antecipadamente — para evitar que expirem no meio do uso.
      security:
        - bearer: []
      parameters:
        - name: id
          in: path
          required: true
          description: ID numérico do shipment
          schema:
            type: integer
            example: 4421
        - name: labelId
          in: path
          required: true
          description: ID da etiqueta
          schema:
            type: string
            example: lbl_xyz
      responses:
        "200":
          description: URL gerada
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  label_id: lbl_xyz
                  format: a4
                  url: https://s3.amazonaws.com/.../label_4421.pdf?X-Amz-Signature=...
                  expires_in: 15 minutos
        "404":
          "$ref": "#/components/responses/NotFound"
        "422":
          description: Etiqueta ainda não disponível
          content:
            "application/json":
              example:
                success: false
                code: 422
                message_code: UNPROCESSABLE_ENTITY
                description: "Etiqueta ainda não disponível. Status: Em processamento"
                data: []
                errors:
                  - Etiqueta ainda não disponível.
  "/api/v1/sellers/orders/enums":
    get:
      tags:
        - Enums de Pedido
      summary: Catálogo de Enums do Pedido
      description: |-
        **Fonte única** dos tipos e valores do ecossistema de pedidos, num só request. Cada chave de `data` é um enum, e cada item traz `value` (o valor que a API aceita/devolve) e `label` (pt-BR pronto para UI). `statuses` e `payment_statuses` também trazem `color` (token de badge).
        
        Use para popular filtros, legendas e badges sem hardcodar listas — os valores só mudam em deploy. Para a versão dos status **agrupada por workflow** (com transições alcançáveis), veja [`GET /api/global/enums/order/status`](/reference/pedidos#tag/enums-de-pedido/GET/api/global/enums/order/status).
        
        > **Nota sobre `event_types`/`event_author_types`:** o `value` é o slug textual (ex.: `status_changed`, `seller`) — o mesmo que aparece em [`GET /orders/{id}/events`](/reference/pedidos#tag/pedidos/GET/api/v1/sellers/orders/{id}/events).
      security:
        - bearer: []
      responses:
        "200":
          description: Catálogo completo de enums do pedido
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  channels:
                    - value: marketplace
                      label: Marketplace
                    - value: website
                      label: Site da Loja
                    - value: direct
                      label: Vendas Diretas
                    - value: store_seller
                      label: Vendedor da Loja
                    - value: physical_store
                      label: Loja Física
                    - value: mobile_app
                      label: App Mobile
                    - value: whatsapp
                      label: WhatsApp
                    - value: pos
                      label: Ponto de Venda
                    - value: api
                      label: API/Integração
                  types:
                    - value: standard
                      label: Padrão
                    - value: production
                      label: Sob Produção
                    - value: pre_order
                      label: Pré-venda
                    - value: backorder
                      label: Sob Encomenda
                    - value: physical_store
                      label: Loja Física
                  workflows:
                    - value: standard
                      label: Padrão
                    - value: production
                      label: Produção
                    - value: in_store_pickup
                      label: Retirada em Loja
                    - value: pre_order
                      label: Pré-venda
                    - value: backorder
                      label: Sob Encomenda
                    - value: collective
                      label: Compra Coletiva
                  statuses:
                    - value: created
                      label: Criado
                      color: gray
                    - value: waiting_payment
                      label: Aguardando Pagamento
                      color: yellow
                    - value: pending
                      label: Pendente
                      color: yellow
                    - value: paid
                      label: Pago
                      color: green
                    - value: in_risk_analysis
                      label: Em análise antifraude
                      color: yellow
                    - value: preparing
                      label: Preparando
                      color: blue
                    - value: ready_to_ship
                      label: Pronto para Envio
                      color: indigo
                    - value: shipped
                      label: Enviado
                      color: indigo
                    - value: delivered
                      label: Entregue
                      color: green
                    - value: cancelled
                      label: Cancelado
                      color: red
                    - value: production_started
                      label: Produção Iniciada
                      color: orange
                    - value: awaiting_materials
                      label: Aguardando Materiais
                      color: amber
                    - value: production_in_progress
                      label: Em Fabricação
                      color: cyan
                    - value: production_finished
                      label: Produção Concluída
                      color: teal
                    - value: reserved
                      label: Reservado
                      color: violet
                    - value: ready_for_pickup
                      label: Pronto para Retirada
                      color: fuchsia
                    - value: picked_up
                      label: Retirado
                      color: emerald
                    - value: pickup_expired
                      label: Retirada Expirada
                      color: rose
                    - value: awaiting_availability
                      label: Aguardando Disponibilidade
                      color: purple
                    - value: available
                      label: Disponível
                      color: lime
                    - value: awaiting_restock
                      label: Aguardando Reposição
                      color: orange
                    - value: restocked
                      label: Reposto
                      color: lime
                    - value: awaiting_campaign_conclusion
                      label: Aguardando Encerramento Campanha
                      color: purple
                    - value: completed
                      label: Concluído
                      color: emerald
                    - value: payment_expired
                      label: Pagamento Expirado
                      color: rose
                  delivery_methods:
                    - value: shipping
                      label: Envio
                    - value: pickup
                      label: Retirada
                  payment_methods:
                    - value: pix
                      label: PIX
                    - value: credit_card
                      label: Cartão de Crédito
                    - value: boleto
                      label: Boleto Bancário
                    - value: boleto_prazo
                      label: Boleto a Prazo
                    - value: other
                      label: Outro
                  payment_statuses:
                    - value: pending
                      label: Pendente
                      color: amber
                    - value: processing
                      label: Processando
                      color: blue
                    - value: waiting_payment
                      label: Aguardando Pagamento
                      color: amber
                    - value: paid
                      label: Pago
                      color: green
                    - value: failed
                      label: Falhou
                      color: red
                    - value: cancelled
                      label: Cancelado
                      color: gray
                    - value: refunded
                      label: Reembolsado
                      color: orange
                  return_statuses:
                    - value: pending
                      label: Aguardando Análise
                    - value: forwarded_to_seller
                      label: Encaminhado ao Vendedor
                    - value: approved
                      label: Aprovado
                    - value: rejected
                      label: Recusado
                    - value: cancelled
                      label: Cancelado pelo Cliente
                    - value: label_generated
                      label: Etiqueta Gerada
                    - value: return_in_progress
                      label: Em Trânsito
                    - value: received
                      label: Recebido
                    - value: refunded
                      label: Estorno Registrado
                    - value: closed
                      label: Encerrado
                  invoice_statuses:
                    - value: pending
                      label: Aguardando
                    - value: validating
                      label: Validando
                    - value: valid
                      label: Válido
                    - value: invalid
                      label: Inválido
                    - value: processing
                      label: Processando
                    - value: completed
                      label: Completado
                    - value: error
                      label: Erro
                  invoice_types:
                    - value: declaration
                      label: Declaração de Conteúdo
                    - value: nfe
                      label: Nota Fiscal Eletrônica
                  event_types:
                    - value: order_created
                      label: Pedido criado
                    - value: status_changed
                      label: Status alterado
                    - value: order_cancelled
                      label: Pedido cancelado
                    - value: preparation_started
                      label: Preparação iniciada
                    - value: shipment_created
                      label: Envio criado
                    - value: tracking_updated
                      label: Rastreio atualizado
                    - value: order_delivered
                      label: Pedido entregue
                    - value: pickup_ready
                      label: Pronto para retirada
                    - value: picked_up
                      label: Retirado pelo cliente
                    - value: invoice_issued
                      label: Nota fiscal emitida
                    - value: payment_confirmed
                      label: Pagamento confirmado
                    - value: refund_requested
                      label: Reembolso solicitado
                    - value: refund_processed
                      label: Reembolso processado
                    - value: delivery_attempt
                      label: Tentativa de entrega
                    - value: delivery_occurrence
                      label: Ocorrência de entrega
                    - value: seller_annotation
                      label: Anotação do seller
                    - value: system_annotation
                      label: Anotação do sistema
                  event_author_types:
                    - value: system
                      label: Sistema
                    - value: admin
                      label: Admin
                    - value: seller
                      label: Seller
                    - value: subagent
                      label: Subconta
                    - value: driver
                      label: Motorista
                    - value: sales_agent
                      label: Representante
                    - value: customer
                      label: Cliente
        "401":
          "$ref": "#/components/responses/Unauthorized"
  "/api/global/enums/order/status":
    get:
      tags:
        - Enums de Pedido
      summary: Status de Pedido (por workflow)
      description: |-
        Catálogo completo dos status de pedido **agrupados por `workflow_type`**. Para cada workflow, devolve apenas os status que um pedido daquele fluxo pode assumir, já com `label` (pt-BR), `color` (token de cor para badge) e `auxiliary` (status secundário/transitório, útil para esconder de filtros principais).
        
        Rota **pública** e cacheada por 24h — a resposta só muda em deploy. Use para montar legendas, filtros e badges sem hardcodar valores. Para as transições válidas a partir do estado atual de um pedido específico, use [`GET /orders/{id}/possible-statuses`](/reference/pedidos#tag/pedidos/GET/api/v1/sellers/orders/{id}/possible-statuses).
      security: []
      responses:
        "200":
          description: Status agrupados por workflow
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  - workflow: standard
                    label: Padrão
                    statuses:
                      - value: paid
                        label: Pago
                        color: green
                        auxiliary: false
                      - value: preparing
                        label: Preparando
                        color: blue
                        auxiliary: false
                      - value: ready_to_ship
                        label: Pronto para Envio
                        color: indigo
                        auxiliary: false
                      - value: shipped
                        label: Enviado
                        color: indigo
                        auxiliary: false
                      - value: delivered
                        label: Entregue
                        color: green
                        auxiliary: false
                      - value: cancelled
                        label: Cancelado
                        color: red
                        auxiliary: false
                  - workflow: in_store_pickup
                    label: Retirada em Loja
                    statuses:
                      - value: reserved
                        label: Reservado
                        color: violet
                        auxiliary: false
                      - value: ready_for_pickup
                        label: Pronto para Retirada
                        color: fuchsia
                        auxiliary: false
                      - value: picked_up
                        label: Retirado
                        color: emerald
                        auxiliary: true
                      - value: pickup_expired
                        label: Retirada Expirada
                        color: rose
                        auxiliary: true
  "/api/logistics/enums/delivery-methods":
    get:
      tags:
        - Enums de Pedido
      summary: Métodos de Entrega
      description: |-
        Lista os métodos de entrega disponíveis. Cada item indica se exige um motorista (`requires_driver`) e se aceita confirmação manual de entrega pelo seller (`allows_manual_confirmation`) — flags que mudam quais ações de logística o integrador pode oferecer.
        
        Rota **pública**.
      security: []
      responses:
        "200":
          description: Métodos de entrega disponíveis
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  - value: with_driver
                    label: Entrega com Motorista
                    requires_driver: true
                    allows_manual_confirmation: false
                  - value: manual_confirmation
                    label: Confirmação Manual
                    requires_driver: false
                    allows_manual_confirmation: true
                  - value: third_party
                    label: Transportadora Terceirizada
                    requires_driver: false
                    allows_manual_confirmation: false
                  - value: pickup_in_store
                    label: Retirada no Local
                    requires_driver: false
                    allows_manual_confirmation: true
  "/api/logistics/enums/shipment-statuses":
    get:
      tags:
        - Enums de Pedido
      summary: Status de Shipment
      description: |-
        Lista os status possíveis de um shipment (envio). Distinto do status do **pedido** — um pedido pode ter vários shipments, cada um com seu próprio ciclo. Cada item traz `value` e `label` (pt-BR).
        
        Rota **pública**.
      security: []
      responses:
        "200":
          description: Status de shipment disponíveis
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  - value: pending
                    label: Pendente
                  - value: processing
                    label: Processando
                  - value: ready_to_ship
                    label: Pronto para Envio
                  - value: in_transit
                    label: Em Trânsito
                  - value: delivered
                    label: Entregue
                  - value: cancelled
                    label: Cancelado
                  - value: return_in_progress
                    label: Em Devolução
                  - value: returned
                    label: Devolvido
                  - value: awaiting_return
                    label: Aguardando Retorno
                  - value: failed
                    label: Falha na Entrega
                  - value: error
                    label: Erro na Integração
  "/api/logistics/enums/shipment-types":
    get:
      tags:
        - Enums de Pedido
      summary: Tipos de Shipment
      description: |-
        Lista os tipos de shipment: venda (`sales_order`), devolução (`return`), transferência entre locais (`transfer`) e coleta (`pickup`). Cada item traz `value` e `label` (pt-BR).
        
        Rota **pública**.
      security: []
      responses:
        "200":
          description: Tipos de shipment disponíveis
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  - value: sales_order
                    label: Pedido de Venda
                  - value: return
                    label: Devolução
                  - value: transfer
                    label: Transferência
                  - value: pickup
                    label: Coleta
  "/api/logistics/enums/freight-table-layouts":
    get:
      tags:
        - Enums de Pedido
      summary: Layouts de Tabela de Frete
      description: |-
        Lista os layouts de tabela de frete aceitos no upload de tabelas próprias. Sem `integration_type` na query, devolve os layouts **nativos** (`default`, `vtex`). Com `?integration_type=<slug>`, devolve os layouts declarados pela integração de transportadora correspondente (ou vazio se o slug for desconhecido).
        
        Rota **pública**.
      security: []
      parameters:
        - name: integration_type
          in: query
          required: false
          description: Slug da integração de transportadora. Quando informado, retorna os layouts suportados por aquela integração.
          schema:
            type: string
            example: j3tms
      responses:
        "200":
          description: Layouts de tabela de frete disponíveis
          content:
            "application/json":
              example:
                success: true
                code: 200
                message_code: SUCCESS
                description: Requisicao realizada com sucesso.
                data:
                  - value: default
                    label: Padrão do Sistema
                    context_fields: []
                  - value: vtex
                    label: Modelo VTEX
                    context_fields: []
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: []
