openapi: 3.0.3

info:
  version: v3
  title: API Merchant da DeliveryVip
  description: >-
    A API Merchant permite que integrações (PDVs, ERPs, operadores de fidelidade e afins) interajam com
    as lojas da plataforma: consumir eventos de pedidos, consultar detalhes e executar ações sobre
    pedidos, além de gerenciar cardápio, cupons, comandas, mesas e o programa de fidelidade. Todos os
    endpoints exigem autenticação com um token de acesso Bearer emitido pela API de autenticação, com
    o escopo `od.all` (as rotas de fidelidade exigem `dv.loyalty`).


    **Erros.** As respostas de erro têm o corpo `{"status": "<código HTTP como string>", "title": "<mensagem>"}`.
    A exceção é o `401`, gerado na validação do token, cujo corpo é `{"title": "Unauthorized", "status": 401}`
    (status numérico). Um `403` por escopo insuficiente vem sem corpo.

servers:
  - url: https://api.deliveryvip.com.br
    description: Produção

security:
  - bearerAuth: []

tags:
  - name: Events
    description: >-
      Mudanças de estado e outras notificações relacionadas aos pedidos e ao salão (mesas e comandas) das lojas.

  - name: Orders
    description: >-
      Pedidos das lojas: consulta e ações de ciclo de vida.

  - name: Discounts
    description: >-
      Cupons e descontos inteligentes da loja. Exige o recurso de descontos (`growth_discount`) contratado pela loja.

  - name: Tabs
    description: >-
      Comandas do salão da loja.

  - name: Places
    description: >-
      Mesas (QR Codes e tablets) do salão da loja.

  - name: Utils
    description: >-
      Endpoints utilitários.

  - name: Merchants
    description: >-
      Dados cadastrais, catálogo e status de funcionamento da loja.

  - name: Loyalty
    description: >-
      Configuração do programa de fidelidade enviada pelo operador de fidelidade (aplicativos que declaram a
      extensão de fidelidade; exige o escopo `dv.loyalty`).


      Observação sobre escopos: os endpoints de configuração abaixo exigem `dv.loyalty`, mas a leitura de
      pedidos — que é como o operador faz o acúmulo, já que o bloco `loyalty` fica no pedido — exige o escopo
      comum `od.all`. Uma integração de operador de fidelidade, portanto, solicita um token com os dois
      escopos (`scope=od.all dv.loyalty`).

  - name: Webhooks
    description: >-
      Eventos enviados ativamente ao aplicativo, em vez de consultados por polling. Um aplicativo com URL de
      webhook configurada recebe cada evento como um POST cujo corpo é um único objeto de evento — o mesmo
      schema retornado pelo endpoint de polling. O evento não traz o bloco `loyalty`: ele fica no pedido,
      que deve ser consultado em `orderURL`. Eventos entregues dessa forma não precisam ser confirmados
      (acknowledgment).


      **Verificação de assinatura (obrigatória).** Todo envio traz estes cabeçalhos:


      - `X-App-Signature` — HMAC-SHA256 em hexadecimal do **corpo bruto da requisição**, usando como chave o
      client secret do aplicativo. Calcule o digest sobre os bytes exatamente como recebidos, antes de
      qualquer parse ou re-serialização do JSON: fazer o parse e codificar de novo altera os bytes e o digest
      não vai bater. Compare usando comparação em tempo constante.
      Para um aplicativo que usa a extensão OpenDelivery, a chave é o **client secret da própria loja**
      (a credencial por loja, `ods_...`) sempre que a loja tiver uma; o client secret do aplicativo só é
      usado para lojas sem credencial própria.
      A renovação de um secret vale imediatamente: toda entrega enviada depois disso, inclusive novas
      tentativas e reenvios manuais, é assinada com o novo secret.

      - `X-App-Id` — identifica a plataforma como remetente.

      - `X-App-MerchantId` — a loja à qual o evento pertence: o `orderingAppMerchantId` do próprio aplicativo
      para aquela loja, quando configurado; caso contrário, o id da loja na plataforma.


      Rejeite qualquer requisição cuja assinatura não confira. A assinatura é a única prova de que o envio
      veio da plataforma, e um endpoint sem verificação permite que qualquer pessoa forje eventos de pedido.
      A assinatura cobre apenas o corpo e não carrega timestamp, então deduplique por `eventId`: uma nova
      tentativa, um reenvio manual ou uma requisição repetida trazem o mesmo `eventId`.


      **Entrega e novas tentativas.** Qualquer 2xx é sucesso. `408` e `429` são tratados como "tente mais
      tarde" e a entrega é repetida até 3 tentativas no total; qualquer outro status fora de 2xx — **inclusive
      5xx** — é tratado como recusa definitiva e não é repetido automaticamente, ficando a entrega disponível
      para reenvio manual. Dez entregas consecutivas com falha suspendem os webhooks do aplicativo até que
      sejam reativados; uma entrega bem-sucedida zera essa contagem.
      Responda 2xx assim que o evento estiver armazenado de forma durável e faça o processamento de forma
      assíncrona: a plataforma usa timeouts curtos (3s para conectar, 5s para leitura) e um endpoint lento é
      registrado como falha.


paths:
  /merchant/v3/events:polling:
    get:
      tags:
        - Events
      summary: Listar eventos
      description: >-
        Consulta (polling) os eventos de pedidos e do salão das lojas autorizadas para o aplicativo autenticado.
        Retorna até 100 eventos por chamada, em ordem cronológica, das últimas 24 horas e ainda não
        confirmados por este aplicativo. Cada evento recebido deve ser confirmado em
        `POST /merchant/v3/events/acknowledgment`; caso contrário, continuará sendo retornado nas próximas
        chamadas.


        Tipos efetivamente emitidos hoje: `CREATED`, `CONFIRMED`, `PREPARING`, `READY_FOR_PICKUP`,
        `DISPATCHED`, `PICKED_UP`, `DELIVERED`, `CONCLUDED` e `CANCELLED` (pedidos) e `CALL_WAITER` e
        `CLOSE_ACCOUNT` (salão). Os demais valores do enum são aceitos como filtro, mas não são gerados.
      parameters:
        - in: header
          name: x-polling-merchants
          description: >-
            Restringe o polling às lojas informadas (ids separados por vírgula). Todas precisam estar
            autorizadas para o aplicativo; caso contrário, a resposta é `403`. Sem o cabeçalho, considera
            todas as lojas autorizadas.
          schema:
            type: array
            items:
              type: string
              format: uuid
        - in: query
          name: eventType
          description: >-
            Filtra pelos tipos de evento. Aceita parâmetro repetido (`eventType=A&eventType=B`), com colchetes
            (`eventType[]=A`) ou valores separados por vírgula. Tipo inválido resulta em `403`.
          schema:
            type: array
            items:
              $ref: "#/components/schemas/eventType"
          style: form
          explode: true
        - in: query
          name: orderType
          description: >-
            Filtra pelo tipo do pedido. Aceita os mesmos formatos de `eventType`. Tipo inválido resulta em `403`.
          schema:
            type: array
            items:
              type: string
              enum:
                - DELIVERY
                - TAKEOUT
                - INDOOR
          style: form
          explode: true
      responses:
        "200":
          description: Lista de eventos pendentes.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/event"
        "204":
          description: Nenhum evento pendente.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: >-
            Filtro inválido (`Invalid eventType`, `Invalid orderType`), loja não autorizada em
            `x-polling-merchants`, cabeçalho vazio ou token sem o escopo `od.all` (neste caso, sem corpo).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "406":
          $ref: "#/components/responses/NotAcceptable"

  /merchant/v3/events/acknowledgment:
    post:
      tags:
        - Events
      summary: Confirmar eventos
      description: >-
        Confirma (acknowledgment) um conjunto de eventos, removendo-os das próximas chamadas de polling deste
        aplicativo. Apenas o `id` de cada item é utilizado; ids desconhecidos ou de lojas não autorizadas são
        ignorados. Confirmar o mesmo evento mais de uma vez não tem efeito adicional.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: O `eventId` do evento a confirmar.
                required:
                  - id
            example:
              - id: 5c7a7b1e-2f9c-4c1e-9a8f-3b2d1e0f4a6b
      responses:
        "202":
          description: Eventos confirmados.
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    description: Quantidade de confirmações efetivamente registradas nesta chamada.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          description: A lista de eventos está vazia.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /merchant/v3/orders/{orderId}:
    get:
      tags:
        - Orders
      summary: Consultar pedido
      description: >-
        Retorna os detalhes de um pedido a partir do seu id. Pedidos aguardando pagamento ou não pagos não são
        retornados (`404`).
      parameters:
        - $ref: "#/components/parameters/orderId"
        - $ref: "#/components/parameters/views"
      responses:
        "200":
          description: Detalhes do pedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/order"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/orders/{orderId}/confirm:
    post:
      tags:
        - Orders
      summary: Confirmar pedido
      description: >-
        Confirma (aceita) o pedido. Não há corpo de requisição.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /merchant/v3/orders/{orderId}/readyForPickup:
    post:
      tags:
        - Orders
      summary: Marcar pedido como pronto
      description: >-
        Sinaliza que o pedido está pronto para ser retirado ou despachado.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /merchant/v3/orders/{orderId}/dispatch:
    post:
      tags:
        - Orders
      summary: Despachar pedido
      description: >-
        Sinaliza que o pedido saiu para entrega.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /merchant/v3/orders/{orderId}/delivered:
    post:
      tags:
        - Orders
      summary: Marcar pedido como entregue
      description: >-
        Sinaliza que o pedido foi entregue ao cliente. Use quando `sendDelivered` for `true` no pedido.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /merchant/v3/orders/{orderId}/requestCancellation:
    post:
      tags:
        - Orders
      summary: Cancelar pedido
      description: >-
        Cancela o pedido. O cancelamento é aplicado na hora (não há etapa de aprovação). Não há corpo de
        requisição.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "200":
          $ref: "#/components/responses/ActionOk"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /merchant/v3/orders/{orderId}/acceptCancellation:
    post:
      tags:
        - Orders
      summary: Aceitar cancelamento
      description: >-
        Aceita uma solicitação de cancelamento do pedido. Mantido por compatibilidade: apenas confirma o
        recebimento e não altera o pedido.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "200":
          $ref: "#/components/responses/ActionOk"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/orders/{orderId}/denyCancellation:
    post:
      tags:
        - Orders
      summary: Recusar cancelamento
      description: >-
        Recusa uma solicitação de cancelamento do pedido. Mantido por compatibilidade: apenas confirma o
        recebimento e não altera o pedido.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "200":
          $ref: "#/components/responses/ActionOk"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/orders/{orderId}/preparing:
    post:
      tags:
        - Orders
      summary: Iniciar preparo do pedido
      description: >-
        Sinaliza que a loja começou a preparar o pedido.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /merchant/v3/orders/{orderId}/pickedUp:
    post:
      tags:
        - Orders
      summary: Marcar pedido como retirado
      description: >-
        Sinaliza que o cliente retirou o pedido (pedidos para retirada). Use quando `sendPickedUp` for `true`
        no pedido.
      parameters:
        - $ref: "#/components/parameters/orderId"
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /merchant/v3/orders/{orderId}/tracking:
    post:
      tags:
        - Orders
      summary: Atualizar rastreamento da entrega
      description: >-
        Envia uma atualização de rastreamento da entrega do pedido. O corpo deve conter `event` (andamento da
        entrega) ou `problem` (ocorrência), além dos blocos opcionais de veículo, previsão, entregador e
        geolocalização. Propriedades fora do schema são rejeitadas com `422`.
      parameters:
        - $ref: "#/components/parameters/orderId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                event:
                  type: object
                  description: Andamento da entrega. Obrigatório quando `problem` não é enviado.
                  required:
                    - type
                    - datetime
                  properties:
                    type:
                      type: string
                      enum:
                        - PICKUP_ONGOING
                        - ARRIVED_AT_MERCHANT
                        - ORDER_PICKED
                        - DELIVERY_ONGOING
                        - ARRIVED_AT_CUSTOMER
                        - ORDER_DELIVERED
                        - CANCELLED
                    message:
                      type: string
                    datetime:
                      type: string
                      format: date-time
                problem:
                  type: object
                  description: Ocorrência na entrega. Obrigatório quando `event` não é enviado.
                  required:
                    - reason
                    - datetime
                  properties:
                    reason:
                      type: string
                      enum:
                        - DELIVERYPERSON_OCCURRENCE
                        - PAYMENT_PROBLEMS
                        - WRONG_PRODUCT_OR_ITEM
                        - ORDER_DELAYED
                        - ORDER_DAMAGED_OR_VIOLATED
                        - CUSTOMER_DID_NOT_PLACE_ORDER
                        - CUSTOMER_ADDRESS_UNKNOWN
                        - ORDER_MISSING_ITEMS
                        - NOBODY_TO_RECEIVE
                        - DELIVERYPERSON_WAITING_PAYMENT_FOR_ALREADY_PAID_ORDER
                        - ORDER_DELIVERED_WITHOUT_PAYMENT
                        - FRAUD_OR_THEFT
                    message:
                      type: string
                    datetime:
                      type: string
                      format: date-time
                vehicle:
                  type: object
                  description: Veículo da entrega.
                  required:
                    - type
                  properties:
                    type:
                      type: string
                      enum:
                        - MOTORBIKE_BAG
                        - MOTORBIKE_BOX
                        - CAR
                        - BICYCLE
                        - SCOOTER
                        - VUC
                    licencePlate:
                      type: string
                      description: Placa do veículo.
                eta:
                  type: object
                  description: Previsões de coleta e entrega.
                  properties:
                    pickupEtaInMinutes:
                      type: integer
                    pickupEtaDatetime:
                      type: string
                      format: date-time
                    deliveryEtaInMinutes:
                      type: integer
                    deliveryEtaDatetime:
                      type: string
                      format: date-time
                    maxDeliveryTime:
                      type: string
                      format: date-time
                deliveryPerson:
                  type: object
                  description: Entregador.
                  properties:
                    id:
                      type: string
                    name:
                      type: string
                    pictureURL:
                      type: string
                      format: uri
                geoLocalization:
                  type: object
                  description: Posição atual do entregador.
                  properties:
                    latitude:
                      type: number
                    longitude:
                      type: number
                    lastAddress:
                      type: object
                      required:
                        - distanceToPickup
                        - distanceToDelivery
                        - timestamp
                      properties:
                        country:
                          type: string
                        state:
                          type: string
                        city:
                          type: string
                        district:
                          type: string
                        street:
                          type: string
                        postalCode:
                          type: string
                        distanceToPickup:
                          type: string
                        distanceToDelivery:
                          type: string
                        timestamp:
                          type: string
                          format: date-time
                externalTrackingURL:
                  type: string
                  format: uri
                  description: URL de acompanhamento da entrega no sistema de logística.
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          description: Corpo fora do schema ou pedido sem logística compatível.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /merchant/v3/{merchantId}/orders:
    get:
      tags:
        - Orders
      summary: Listar pedidos
      description: >-
        Lista os pedidos da loja, do mais recente para o mais antigo, com paginação por cursor. Quando há mais
        páginas, a resposta traz os cabeçalhos `X-Next-Cursor`/`X-Previous-Cursor` e `Link` (`rel="next"` e
        `rel="prev"`).
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - in: query
          name: orderType[]
          description: Filtra pelo tipo do pedido.
          schema:
            type: array
            items:
              type: string
              enum:
                - DELIVERY
                - TAKEOUT
                - INDOOR
                - DINE_IN
        - in: query
          name: starts_at
          description: Data inicial (inclusive). Se informada sem `ends_in`, vai até o fim do dia atual.
          schema:
            type: string
            format: date
        - in: query
          name: ends_in
          description: Data final (inclusive). Exige `starts_at`.
          schema:
            type: string
            format: date
        - $ref: "#/components/parameters/views"
        - $ref: "#/components/parameters/perPage"
        - $ref: "#/components/parameters/next"
        - $ref: "#/components/parameters/previous"
      responses:
        "200":
          description: Página de pedidos.
          headers:
            X-Next-Cursor:
              $ref: "#/components/headers/X-Next-Cursor"
            X-Previous-Cursor:
              $ref: "#/components/headers/X-Previous-Cursor"
            Link:
              $ref: "#/components/headers/Link"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/order"
        "204":
          description: Nenhum pedido encontrado.
        "400":
          $ref: "#/components/responses/BadRequestCursor"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "406":
          $ref: "#/components/responses/NotAcceptable"

  /merchant/v3/{merchantId}/discounts:
    get:
      tags:
        - Discounts
      summary: Listar descontos
      description: >-
        Lista os descontos (cupons e descontos inteligentes) da loja, com paginação por cursor.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/perPage"
        - $ref: "#/components/parameters/next"
        - $ref: "#/components/parameters/previous"
      responses:
        "200":
          description: Página de descontos.
          headers:
            X-Next-Cursor:
              $ref: "#/components/headers/X-Next-Cursor"
            X-Previous-Cursor:
              $ref: "#/components/headers/X-Previous-Cursor"
            Link:
              $ref: "#/components/headers/Link"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/discount"
        "204":
          description: Nenhum desconto encontrado.
        "400":
          $ref: "#/components/responses/BadRequestCursor"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DiscountNotHired"
        "404":
          $ref: "#/components/responses/NotFound"

    post:
      tags:
        - Discounts
      summary: Criar desconto
      description: >-
        Cria um cupom (`COUPON`, identificado por `code`) ou um desconto inteligente (`SMART`, identificado por
        `name`). O corpo pode ser enviado diretamente ou envolvido em `{"discount": {...}}`. Os valores de enum
        são aceitos em maiúsculas ou minúsculas.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/discountInput"
      responses:
        "200":
          description: Desconto criado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/discount"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DiscountNotHired"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

  /merchant/v3/{merchantId}/discounts/{discountId}:
    get:
      tags:
        - Discounts
      summary: Consultar desconto
      description: >-
        Retorna os detalhes de um desconto a partir do seu id.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/discountId"
      responses:
        "200":
          description: Detalhes do desconto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/discount"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DiscountNotHired"
        "404":
          $ref: "#/components/responses/NotFound"

    patch:
      tags:
        - Discounts
      summary: Atualizar desconto
      description: >-
        Atualiza um desconto da loja. Envie apenas os campos que deseja alterar; o corpo pode ser enviado
        diretamente ou envolvido em `{"discount": {...}}`.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/discountId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/discountInput"
      responses:
        "200":
          description: Desconto atualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/discount"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DiscountNotHired"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

    delete:
      tags:
        - Discounts
      summary: Excluir desconto
      description: >-
        Exclui um desconto da loja e retorna o desconto excluído.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/discountId"
      responses:
        "200":
          description: Desconto excluído.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/discount"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DiscountNotHired"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}/discounts/{discountId}/available:
    post:
      tags:
        - Discounts
      summary: Ativar desconto
      description: >-
        Torna o desconto disponível para uso.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/discountId"
      responses:
        "200":
          description: Desconto ativado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/discount"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DiscountNotHired"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}/discounts/{discountId}/unavailable:
    post:
      tags:
        - Discounts
      summary: Desativar desconto
      description: >-
        Torna o desconto indisponível para uso.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/discountId"
      responses:
        "200":
          description: Desconto desativado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/discount"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DiscountNotHired"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}/discounts/{discountId}/stats:
    get:
      tags:
        - Discounts
      summary: Consultar estatísticas do desconto
      description: >-
        Retorna as estatísticas de uso de um desconto: valores totais, quantidade de pedidos e clientes novos
        ou reativados.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/discountId"
      responses:
        "200":
          description: Estatísticas do desconto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/discountStats"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DiscountNotHired"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}/tabs:
    get:
      tags:
        - Tabs
      summary: Listar comandas
      description: >-
        Lista as comandas da loja.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "200":
          description: Lista de comandas.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/tab"
        "204":
          description: Nenhuma comanda encontrada.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

    post:
      tags:
        - Tabs
      summary: Criar comanda
      description: >-
        Cria uma comanda na loja. O corpo pode ser enviado diretamente ou envolvido em `{"tab": {...}}`.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/tabInput"
      responses:
        "201":
          description: Comanda criada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/tab"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

  /merchant/v3/{merchantId}/tabs/{tabId}:
    get:
      tags:
        - Tabs
      summary: Consultar comanda
      description: >-
        Retorna os detalhes de uma comanda a partir do seu id.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/tabId"
      responses:
        "200":
          description: Detalhes da comanda.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/tab"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

    patch:
      tags:
        - Tabs
      summary: Atualizar comanda
      description: >-
        Atualiza o nome ou o código de uma comanda. O corpo pode ser enviado diretamente ou envolvido em
        `{"tab": {...}}`.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/tabId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/tabInput"
      responses:
        "200":
          description: Comanda atualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/tab"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

    delete:
      tags:
        - Tabs
      summary: Excluir comanda
      description: >-
        Exclui uma comanda da loja e retorna a comanda excluída.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/tabId"
      responses:
        "200":
          description: Comanda excluída.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/tab"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}/tabs/{tabId}/available:
    post:
      tags:
        - Tabs
      summary: Disponibilizar comanda
      deprecated: true
      description: >-
        Torna a comanda disponível. **Descontinuado:** as respostas trazem os cabeçalhos `Deprecation` e
        `Sunset` (01/12/2025).
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/tabId"
      responses:
        "202":
          description: Comanda disponibilizada.
          headers:
            Deprecation:
              $ref: "#/components/headers/Deprecation"
            Sunset:
              $ref: "#/components/headers/Sunset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/actionResult"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

  /merchant/v3/{merchantId}/tabs/{tabId}/unavailable:
    post:
      tags:
        - Tabs
      summary: Indisponibilizar comanda
      deprecated: true
      description: >-
        Torna a comanda indisponível. **Descontinuado:** as respostas trazem os cabeçalhos `Deprecation` e
        `Sunset` (01/12/2025).
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/tabId"
      responses:
        "202":
          description: Comanda indisponibilizada.
          headers:
            Deprecation:
              $ref: "#/components/headers/Deprecation"
            Sunset:
              $ref: "#/components/headers/Sunset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/actionResult"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

  /merchant/v3/{merchantId}/tabs/{tabId}/opened:
    post:
      tags:
        - Tabs
      summary: Abrir comanda
      description: >-
        Abre uma comanda que estava fechada.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/tabId"
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

  /merchant/v3/{merchantId}/tabs/{tabId}/closed:
    post:
      tags:
        - Tabs
      summary: Fechar comanda
      description: >-
        Fecha uma comanda que está aberta.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/tabId"
      responses:
        "202":
          $ref: "#/components/responses/ActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

  /merchant/v3/{merchantId}/places:
    get:
      tags:
        - Places
      summary: Listar mesas
      description: >-
        Lista as mesas da loja (QR Codes e tablets de salão) e a situação de cada uma.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "200":
          description: Lista de mesas.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/place"
        "204":
          description: Nenhuma mesa encontrada.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}/places/{placeId}/opened:
    post:
      tags:
        - Places
      summary: Abrir mesa
      description: >-
        Abre uma mesa que estava fechada.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/placeId"
      responses:
        "202":
          $ref: "#/components/responses/PlaceActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

  /merchant/v3/{merchantId}/places/{placeId}/closed:
    post:
      tags:
        - Places
      summary: Fechar mesa
      description: >-
        Fecha uma mesa que está aberta.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/placeId"
      responses:
        "202":
          $ref: "#/components/responses/PlaceActionAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ValidationFailed"

  /merchant/v3/{merchantId}/delivery-fee/{latitude}/{longitude}:
    get:
      tags:
        - Utils
      summary: Calcular taxa de entrega
      description: >-
        Calcula a taxa de entrega da loja para uma coordenada, conforme as áreas ou raios de entrega
        configurados. Fora da área atendida, `status` é `UNAVAILABLE` e `fee` não é retornado.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - in: path
          name: latitude
          description: Latitude do endereço, em graus decimais (por exemplo, `-23.54809`).
          required: true
          schema:
            type: string
            pattern: "^-?\\d+(.\\d+)?$"
        - in: path
          name: longitude
          description: Longitude do endereço, em graus decimais (por exemplo, `-46.63638`).
          required: true
          schema:
            type: string
            pattern: "^-?\\d+(.\\d+)?$"
      responses:
        "200":
          description: Resultado do cálculo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/deliveryFee"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}:
    get:
      tags:
        - Merchants
      summary: Consultar loja
      description: |-
        Retorna todos os dados de uma loja: informações básicas, serviços, formas de pagamento e catálogo
        (complementos, grupos de complementos, categorias e itens).
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "200":
          description: Dados da loja.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Merchant"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}/merchantUpdate:
    post:
      tags:
        - Merchants
      summary: Atualizar loja
      description: |-
        Atualiza status e entidades **já existentes** da loja. Entidades inexistentes não são criadas.
        O corpo pode ser enviado diretamente ou envolvido em `{"merchant": {...}}`.

        Este endpoint pode ser usado das seguintes formas:

        **1 - Enviado apenas com o campo `merchantStatus`:**
        abre ou fecha a loja.

        **2 - Enviado apenas com os campos `entityType` e `updatedObjects`:**
        atualiza somente os objetos enviados.
        > Quando o campo `entityType` é preenchido, o campo `updatedObjects` não pode estar vazio.

        **3 - Enviado com os campos `merchantStatus`, `entityType` e `updatedObjects`:**
        os cenários 1 e 2 acontecem simultaneamente.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MerchantUpdate"
      responses:
        "204":
          description: Dados recebidos e processados com sucesso. Sem conteúdo na resposta.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/MalformedJson"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/CatalogUnprocessable"

  /merchant/v3/{merchantId}/merchantUpsert:
    post:
      tags:
        - Merchants
      summary: Criar ou atualizar entidades da loja
      description: |-
        Cria ou atualiza (upsert) status e entidades da loja. O corpo pode ser enviado diretamente ou
        envolvido em `{"merchant": {...}}`.

        Este endpoint pode ser usado das seguintes formas:

        **1 - Enviado apenas com o campo `merchantStatus`:**
        abre ou fecha a loja.

        **2 - Enviado apenas com os campos `entityType` e `upsertObjects`:**
        cria ou atualiza somente os objetos enviados.
        > Quando o campo `entityType` é preenchido, o campo `upsertObjects` não pode estar vazio.

        **3 - Enviado com os campos `merchantStatus`, `entityType` e `upsertObjects`:**
        os cenários 1 e 2 acontecem simultaneamente.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MerchantUpsert"
      responses:
        "204":
          description: Dados recebidos e processados com sucesso. Sem conteúdo na resposta.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/MalformedJson"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/CatalogUnprocessable"

  /merchant/v3/{merchantId}/merchantForce:
    post:
      tags:
        - Merchants
      summary: Sincronizar loja completa
      description: |-
        Envia a loja completa (mesmo formato de `GET /merchant/v3/{merchantId}`) e processa todas as entidades
        presentes: serviços, complementos, grupos de complementos, categorias, itens e formas de pagamento.
        O campo `status` abre ou fecha a loja. Os campos `id`, `lastUpdate`, `ttl` e `status` são obrigatórios.
        No envio, `basicInfo.contactPhones` deve ser uma lista de objetos. O corpo pode ser enviado diretamente
        ou envolvido em `{"merchant": {...}}`.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Merchant"
      responses:
        "204":
          description: Dados recebidos e processados com sucesso. Sem conteúdo na resposta.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/MalformedJson"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/CatalogUnprocessable"

  /merchant/v3/{merchantId}/status:
    get:
      tags:
        - Merchants
      summary: Consultar status e horários da loja
      description: >-
        Retorna o status da loja (`AVAILABLE`/`UNAVAILABLE`), os horários de funcionamento e o id da loja.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "200":
          description: Status e horários da loja.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    description: Indica se a loja está aberta (`AVAILABLE`) ou fechada (`UNAVAILABLE`).
                    enum:
                      - AVAILABLE
                      - UNAVAILABLE
                  services:
                    type: array
                    description: Sempre um único elemento com os horários da loja.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: Id da loja.
                        serviceHours:
                          type: array
                          items:
                            type: object
                            properties:
                              weekHours:
                                type: array
                                description: Um elemento por faixa de horário de cada dia da semana.
                                items:
                                  type: object
                                  properties:
                                    dayOfWeek:
                                      type: array
                                      items:
                                        type: string
                                        enum:
                                          - MONDAY
                                          - TUESDAY
                                          - WEDNESDAY
                                          - THURSDAY
                                          - FRIDAY
                                          - SATURDAY
                                          - SUNDAY
                                    timePeriods:
                                      type: object
                                      description: Faixa de horário no horário local da loja.
                                      properties:
                                        startTime:
                                          type: string
                                          example: "10:00:00"
                                        endTime:
                                          type: string
                                          example: "22:00:00"
                  orderingAppMerchantId:
                    type: string
                    format: uuid
                    description: Id da loja na plataforma.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /merchant/v3/{merchantId}/loyalty/config:
    put:
      tags:
        - Loyalty
      summary: Enviar configuração de fidelidade
      description: >-
        Cria ou substitui a configuração do programa de fidelidade do aplicativo autenticado para a loja
        (a última escrita prevalece). Antes de gravar qualquer coisa, a plataforma faz uma verificação
        síncrona: um GET /loyalty/ping assinado contra o `api_base_url` da extensão. Se o operador estiver
        inacessível ou a verificação da assinatura falhar, nada é gravado e a resposta é `422`. Exige o
        escopo `dv.loyalty` e a extensão de fidelidade declarada no aplicativo.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/loyaltyConfig"
      responses:
        "200":
          description: Configuração gravada. Retorna a configuração persistida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/loyaltyConfig"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: O token não tem o escopo `dv.loyalty` (sem corpo).
        "404":
          description: Loja não encontrada ou sem o aplicativo instalado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "422":
          description: >-
            Falha de validação (`balanceTypes` deve incluir `cashback`; id e nome do programa são obrigatórios;
            `program` e `capabilities` são obrigatórios), o aplicativo não declara a extensão de fidelidade
            (`loyalty_extension_not_declared`) ou a verificação síncrona por ping falhou (nada foi gravado).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    delete:
      tags:
        - Loyalty
      summary: Remover configuração de fidelidade
      description: >-
        Desativa o programa na loja removendo a configuração gravada. Idempotente: sempre responde `204`,
        exista ou não uma configuração. Os vínculos de clientes e o histórico de resgates não são alterados.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "204":
          description: Configuração removida (ou não existia).
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: O token não tem o escopo `dv.loyalty` (sem corpo).
        "404":
          description: Loja não encontrada ou sem o aplicativo instalado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

components:
  parameters:
    merchantId:
      in: path
      name: merchantId
      description: Id (UUID) da loja na plataforma. A loja precisa estar autorizada para o aplicativo.
      required: true
      schema:
        type: string
        format: uuid
    orderId:
      in: path
      name: orderId
      description: Id (UUID) do pedido.
      required: true
      schema:
        type: string
        format: uuid
    discountId:
      in: path
      name: discountId
      description: Id (UUID) do desconto.
      required: true
      schema:
        type: string
        format: uuid
    tabId:
      in: path
      name: tabId
      description: Id (UUID) da comanda.
      required: true
      schema:
        type: string
        format: uuid
    placeId:
      in: path
      name: placeId
      description: Id da mesa (QR Code ou tablet), como retornado em `GET /merchant/v3/{merchantId}/places`.
      required: true
      schema:
        type: string
    views:
      in: query
      name: views[]
      description: >-
        Formato dos complementos dos itens. Por padrão, os complementos vêm achatados em `items[].options`.
        Com `optionGroups`, vêm agrupados em `items[].optionGroups`. `groupOptions` é o nome antigo do
        agrupamento (gera `items[].optionsGroup`) e está descontinuado.
      schema:
        type: array
        items:
          type: string
          enum:
            - optionGroups
            - groupOptions
    perPage:
      in: query
      name: per_page
      description: Itens por página. Padrão 30; valores informados são limitados entre 30 e 250.
      schema:
        type: integer
        minimum: 30
        maximum: 250
        default: 30
    next:
      in: query
      name: next
      description: Cursor da próxima página (valor de `X-Next-Cursor`). Não pode ser combinado com `previous`.
      schema:
        type: string
    previous:
      in: query
      name: previous
      description: Cursor da página anterior (valor de `X-Previous-Cursor`). Não pode ser combinado com `next`.
      schema:
        type: string

  headers:
    X-Next-Cursor:
      description: Cursor da próxima página, quando existir.
      schema:
        type: string
    X-Previous-Cursor:
      description: Cursor da página anterior, quando existir.
      schema:
        type: string
    Link:
      description: Links de paginação (`rel="next"` e `rel="prev"`), quando existirem.
      schema:
        type: string
    Deprecation:
      description: Indica que o endpoint está descontinuado.
      schema:
        type: string
        example: "true"
    Sunset:
      description: Data a partir da qual o endpoint pode deixar de existir.
      schema:
        type: string
        example: Mon, 01 Dec 2025 00:00:00 GMT

  schemas:
    eventType:
      type: string
      description: Tipo do evento.
      enum:
        - CREATED
        - CONFIRMED
        - PREPARING
        - DISPATCHED
        - READY_FOR_PICKUP
        - PICKUP_AREA_ASSIGNED
        - PICKED_UP
        - DELIVERED
        - CONCLUDED
        - CANCELLATION_REQUESTED
        - CANCELLATION_REQUEST_DENIED
        - CANCELLED
        - ORDER_CANCELLATION_REQUEST
        - CLOSE_ACCOUNT
        - CALL_WAITER

    event:
      type: object
      description: >-
        Evento de pedido ou do salão. Eventos de pedido trazem `orderId`, `orderURL` e `orderType`; eventos do
        salão (`CALL_WAITER`, `CLOSE_ACCOUNT`) trazem os campos de mesa/comanda presentes no evento.
      properties:
        eventId:
          type: string
          format: uuid
          description: Id do evento. Use-o para confirmar o evento e para deduplicar entregas.
        createdAt:
          type: string
          format: date-time
          description: Data e hora do evento, com o fuso da plataforma.
        merchantId:
          type: string
          description: >-
            Id da loja: o id que o aplicativo usa para a loja (`orderingAppMerchantId`), quando configurado;
            caso contrário, o UUID da loja na plataforma.
        eventType:
          $ref: "#/components/schemas/eventType"
        metadata:
          type: object
          description: Dados adicionais do evento. Omitido quando vazio.
          properties:
            clientId:
              type: string
              description: Aplicativo que originou a confirmação ou o cancelamento, quando houver.
            reason:
              type: string
              description: Motivo do cancelamento.
            code:
              type: string
              description: Código do motivo do cancelamento.
              example: OTHER_CANCELLATION_REASON
            tab:
              type: string
            tabId:
              type: string
              format: uuid
            tabCode:
              type: string
            tabName:
              type: string
            placeName:
              type: string
            placeId:
              type: string
        orderId:
          type: string
          format: uuid
          description: Id do pedido (eventos de pedido).
        orderURL:
          type: string
          format: uri
          description: >-
            URL para consultar o pedido. Para lojas integradas via OpenDelivery, aponta para a API OpenDelivery
            (`/v1/orders/{orderId}`); caso contrário, para `GET /merchant/v3/orders/{orderId}`.
        orderType:
          type: string
          description: Tipo do pedido (eventos de pedido).
          enum:
            - DELIVERY
            - TAKEOUT
            - INDOOR
        placeName:
          type: string
          description: Nome ou local da mesa (eventos do salão).
        placeId:
          type: string
          description: Id da mesa (eventos do salão).
        tab:
          type: string
          description: Código da comanda (eventos do salão).
        tabId:
          type: string
          format: uuid
          description: Id da comanda (eventos do salão).
        tabCode:
          type: string
          description: Código da comanda (eventos do salão).
        tabName:
          type: string
          description: Nome da comanda (eventos do salão).

    loyaltyConfig:
      type: object
      required:
        - program
        - capabilities
      properties:
        program:
          type: object
          required:
            - id
            - name
          properties:
            id:
              type: string
              description: Identificador do programa no operador.
            name:
              type: string
              description: Nome do programa.
            ownerType:
              type: string
              description: Titular do programa.
              enum:
                - store
                - chain
                - coalition
              default: store
            rulesUrl:
              type: string
              format: uri
              description: URL do regulamento do programa.
        capabilities:
          type: object
          required:
            - balanceTypes
          properties:
            balanceTypes:
              type: array
              items:
                type: string
                enum:
                  - cashback
              description: Deve incluir `cashback` (o único tipo de saldo na v1).
            partialRedemption:
              type: boolean
              default: true
              description: Se o cliente pode resgatar só parte do saldo.
            enrollment:
              type: boolean
              default: true
              description: Se o operador aceita a adesão de novos clientes pela plataforma.
            redemptionLimits:
              type: object
              description: >-
                Limites comerciais opcionais por pedido. Omita o objeto, ou qualquer um dos limites, para não
                declarar limite ali. Percentuais incidem sobre a base resgatável — os itens do pedido menos os
                demais descontos do carrinho; frete e taxas nunca são resgatáveis, então um teto percentual é
                calculado sobre os itens, não sobre o total do pedido.
              properties:
                min:
                  $ref: "#/components/schemas/redemptionLimit"
                max:
                  $ref: "#/components/schemas/redemptionLimit"

    redemptionLimit:
      type: object
      description: >-
        Um único limite: valor fixo em BRL ou percentual da base resgatável. Um mínimo nunca aumenta o valor
        resgatado — apenas decide se o resgate é possível.
      required:
        - type
        - value
      properties:
        type:
          type: string
          enum:
            - fixed
            - percent
        value:
          type: number
          description: Valor em BRL quando `type` é `fixed`; de 0 a 100 quando `type` é `percent`.

    loyaltyBlock:
      type: object
      description: >-
        Presente no pedido apenas para aplicativos cujo programa de fidelidade o cliente aderiu. Cada
        aplicativo recebe somente o bloco do seu próprio programa.


        O bloco identifica o cliente no operador e informa o que foi resgatado neste pedido. Ele não traz
        nenhum valor calculado pela plataforma: as regras de acúmulo pertencem ao operador, que escolhe sua
        própria base a partir do `total` do pedido (por exemplo, `itemsPrice` menos `discount`, se frete e
        taxas não devem acumular).


        O bloco descreve o pedido como ele está no momento da leitura, não um instante do seu histórico. Um
        aplicativo que recebe um evento CONCLUDED consulta o pedido e faz o acúmulo; um que recebe um evento
        CANCELLED estorna o acúmulo que havia concedido para aquele pedido.


        Quando um resgate está REVERSED, o saldo voltou para o cliente, que portanto pagou esse valor por
        outros meios — mas os totais do pedido continuam mostrando o desconto que ele havia financiado. Some
        `redemption.amount.value` de volta a qualquer base derivada dos totais do pedido. Um pedido que nunca
        teve resgate não traz a chave `redemption`.
      required:
        - accountId
        - programId
      properties:
        accountId:
          type: string
          description: Identificador da conta do cliente no operador.
        programId:
          type: string
          description: Identificador do programa no operador.
        redemption:
          type: object
          description: >-
            O resgate debitado neste pedido, presente somente na entrega para o aplicativo que foi debitado.
            CONFIRMED significa que o resgate vale: o desconto que ele financia está dentro de
            `total.discount` do pedido. REVERSED significa que o saldo foi devolvido ao cliente.
          required:
            - externalId
            - status
            - amount
          properties:
            externalId:
              type: string
              description: Identificador do resgate gerado pelo operador quando o débito foi criado.
            status:
              type: string
              enum:
                - CONFIRMED
                - REVERSED
            amount:
              $ref: "#/components/schemas/money"

    money:
      type: object
      description: Valor monetário.
      required:
        - value
        - currency
      properties:
        value:
          type: number
          description: Valor, com até 4 casas decimais.
          example: 39.9
        currency:
          type: string
          description: Moeda (código ISO 4217).
          enum:
            - BRL

    orderOption:
      type: object
      description: Complemento escolhido em um item do pedido.
      properties:
        id:
          type: string
          format: uuid
        index:
          type: integer
          description: Posição do complemento na lista.
        name:
          type: string
        externalCode:
          type: string
          description: Código externo do complemento. Omitido quando vazio.
        unit:
          type: string
          description: Unidade de medida. Sempre `UN`.
          enum:
            - UN
        quantity:
          type: integer
        unitPrice:
          $ref: "#/components/schemas/money"
        totalPrice:
          $ref: "#/components/schemas/money"

    orderOptionGroup:
      type: object
      description: Grupo de complementos de um item do pedido (views `optionGroups`/`groupOptions`).
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        externalCode:
          type: string
          description: Código externo do grupo. Omitido quando vazio.
        totalPrice:
          $ref: "#/components/schemas/money"
        options:
          type: array
          items:
            $ref: "#/components/schemas/orderOption"

    address:
      type: object
      description: Endereço.
      properties:
        country:
          type: string
          description: Sigla do país.
          example: BR
        state:
          type: string
          description: Sigla do estado.
          example: SP
        city:
          type: string
          example: São Paulo
        district:
          type: string
          description: Bairro.
          example: Moema
        street:
          type: string
          description: Logradouro.
          example: Avenida Ibirapuera
        number:
          type: string
          example: "100"
        complement:
          type: string
          description: Complemento. Omitido quando vazio.
          example: Bloco 2, apto 31
        reference:
          type: string
          description: Ponto de referência. Omitido quando vazio.
          example: Casa amarela
        postalCode:
          type: string
          description: CEP.
          example: 04029-000
        formattedAddress:
          type: string
          description: Endereço completo formatado.
        coordinates:
          type: object
          properties:
            latitude:
              type: number
              example: -23.54809
            longitude:
              type: number
              example: -46.63638

    order:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Id do pedido.
        type:
          type: string
          description: Tipo do pedido. Pedidos de consumo no local são retornados como `INDOOR`.
          enum:
            - DELIVERY
            - TAKEOUT
            - INDOOR
        displayId:
          type: string
          description: Código curto do pedido, exibido para a loja e o cliente.
        salesChannel:
          type: string
          description: Canal de venda do pedido.
          enum:
            - STORE
            - MARKETPLACE
            - TABLET
            - QRCODE
            - TAB
        createdAt:
          type: string
          format: date-time
          description: Data e hora de criação do pedido.
        orderTiming:
          type: string
          description: Pedido imediato ou agendado.
          enum:
            - INSTANT
            - SCHEDULED
        preparationStartDateTime:
          type: string
          format: date-time
          description: Início previsto do preparo (atualmente igual a `createdAt`).
        lastEvent:
          type: string
          description: >-
            Último evento do pedido, derivado do seu estado atual. Omitido quando o estado não corresponde a
            nenhum destes valores.
          enum:
            - CREATED
            - CONFIRMED
            - READY_FOR_PICKUP
            - CONCLUDED
            - CANCELLED
        merchant:
          type: object
          properties:
            id:
              type: string
              description: >-
                Id da loja: o id que o aplicativo usa para a loja (`orderingAppMerchantId`), quando configurado;
                caso contrário, o UUID da loja na plataforma.
            name:
              type: string
        items:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              index:
                type: integer
                description: Posição do item no pedido.
              name:
                type: string
              externalCode:
                type: string
                description: Código externo do item. Omitido quando vazio.
              unit:
                type: string
                description: Unidade de medida. Sempre `UN`.
                enum:
                  - UN
              ean:
                type: string
                description: Código EAN. Omitido quando vazio.
              quantity:
                type: integer
              specialInstructions:
                type: string
                description: Observação do cliente para o item. Omitida quando vazia.
              unitPrice:
                $ref: "#/components/schemas/money"
              optionsPrice:
                $ref: "#/components/schemas/money"
              totalPrice:
                $ref: "#/components/schemas/money"
              options:
                type: array
                description: Complementos escolhidos (formato padrão). Omitido quando o item não tem complementos.
                items:
                  $ref: "#/components/schemas/orderOption"
              optionGroups:
                type: array
                description: Complementos agrupados (view `optionGroups`).
                items:
                  $ref: "#/components/schemas/orderOptionGroup"
              optionsGroup:
                type: array
                deprecated: true
                description: Complementos agrupados (view `groupOptions`, descontinuada).
                items:
                  $ref: "#/components/schemas/orderOptionGroup"
        otherFees:
          type: array
          description: Taxas do pedido. Presente apenas em pedidos de entrega.
          items:
            type: object
            properties:
              name:
                type: string
              type:
                type: string
                enum:
                  - DELIVERY_FEE
                  - SERVICE_FEE
                  - TIP
                  - MIN_ORDER_FEE
              receivedBy:
                type: string
                enum:
                  - MARKETPLACE
                  - MERCHANT
                  - LOGISTIC_SERVICES
              receiverDocument:
                type: string
              price:
                $ref: "#/components/schemas/money"
        discounts:
          type: array
          description: Descontos aplicados. Omitido quando o pedido não tem desconto.
          items:
            type: object
            properties:
              amount:
                $ref: "#/components/schemas/money"
              target:
                type: string
                description: Sobre o que o desconto incide.
                enum:
                  - CART
                  - DELIVERY_FEE
              sponsorshipValues:
                type: array
                description: Quem financia o desconto.
                items:
                  type: object
                  properties:
                    name:
                      type: string
                      enum:
                        - MARKETPLACE
                        - MERCHANT
                    amount:
                      $ref: "#/components/schemas/money"
                    discountCode:
                      type: string
                      description: Código ou título do desconto.
        total:
          type: object
          description: Totais do pedido.
          properties:
            itemsPrice:
              $ref: "#/components/schemas/money"
            otherFees:
              $ref: "#/components/schemas/money"
            discount:
              $ref: "#/components/schemas/money"
            orderAmount:
              $ref: "#/components/schemas/money"
        payments:
          type: object
          properties:
            prepaid:
              type: number
              description: Valor já pago online.
            pending:
              type: number
              description: Valor a receber na entrega ou retirada.
            methods:
              type: array
              items:
                type: object
                properties:
                  value:
                    type: number
                  currency:
                    type: string
                    enum:
                      - BRL
                  type:
                    type: string
                    description: Momento do pagamento.
                    enum:
                      - PREPAID
                      - PENDING
                      - ONLINE
                      - OFFLINE
                  method:
                    type: string
                    description: Forma de pagamento.
                    enum:
                      - CREDIT
                      - DEBIT
                      - MEAL_VOUCHER
                      - FOOD_VOUCHER
                      - DIGITAL_WALLET
                      - PIX
                      - CASH
                      - CREDIT_DEBIT
                      - COUPON
                      - REDEEM
                      - PREPAID_REDEEM
                      - OTHER
                  brand:
                    type: string
                    description: Bandeira. Omitida quando não se aplica.
                    example: VISA
                  methodInfo:
                    type: string
                    description: Informação adicional da forma de pagamento. Omitida quando vazia.
                  changeFor:
                    type: number
                    description: Valor para o qual levar troco. Presente apenas quando há troco.
        loyalty:
          $ref: "#/components/schemas/loyaltyBlock"
        customer:
          type: object
          description: Cliente. Omitido quando o pedido não tem nome de comprador.
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string
            documentNumber:
              type: string
              description: CPF/CNPJ do cliente. Omitido quando não informado.
            phone:
              type: object
              properties:
                number:
                  type: string
                  description: Telefone no formato E.164, sem formatação.
                  example: "5511999999999"
            email:
              type: string
              description: E-mail. Omitido para clientes convidados (sem cadastro).
            ordersCountOnMerchant:
              type: integer
              description: Quantidade de pedidos do cliente na loja.
        schedule:
          type: object
          description: Janela do agendamento. Presente apenas em pedidos agendados.
          properties:
            scheduledDateTimeStart:
              type: string
              format: date-time
            scheduledDateTimeEnd:
              type: string
              format: date-time
        delivery:
          type: object
          description: Dados da entrega. Presente apenas em pedidos de entrega.
          properties:
            deliveredBy:
              type: string
              enum:
                - MERCHANT
            estimatedDeliveryDateTime:
              type: string
              format: date-time
            deliveryAddress:
              $ref: "#/components/schemas/address"
        takeout:
          type: object
          description: Dados da retirada. Presente apenas em pedidos para retirada.
          properties:
            mode:
              type: string
              enum:
                - DEFAULT
            takeoutDateTime:
              type: string
              format: date-time
        indoor:
          type: object
          description: Dados do consumo no local. Presente apenas em pedidos `INDOOR`.
          properties:
            mode:
              type: string
              description: >-
                `DEFAULT` para consumo no local sem mesa/comanda, `TAB` para pedidos em comanda e `PLACE` para
                pedidos em mesa.
              enum:
                - DEFAULT
                - PLACE
                - TAB
            indoorDateTime:
              type: string
              format: date-time
            place:
              type: string
            placeName:
              type: string
            placeId:
              type: string
            tab:
              type: string
            tabId:
              type: string
              format: uuid
            tabName:
              type: string
            tabCode:
              type: string
        sendDelivered:
          type: boolean
          description: A loja é responsável pelo evento DELIVERED (sem operador logístico externo).
        sendPreparing:
          type: boolean
          description: A loja deve enviar o evento PREPARING.
        sendPickedUp:
          type: boolean
          description: A loja é responsável pelo evento PICKED_UP (pedidos para retirada).
        sendTracking:
          type: boolean
          description: A loja deve enviar atualizações de rastreamento.
        extraInfo:
          type: string
          description: Observação geral do pedido. Omitida quando vazia.

    discountInput:
      type: object
      properties:
        type:
          type: string
          description: Tipo do desconto.
          enum:
            - COUPON
            - SMART
        code:
          type: string
          description: Código do cupom (`COUPON`).
        name:
          type: string
          description: Nome do desconto inteligente (`SMART`).
        startsAt:
          type: string
          format: date-time
          description: Início da vigência.
        endsAt:
          type: string
          format: date-time
          description: Fim da vigência (opcional).
        rules:
          type: object
          properties:
            valueType:
              type: string
              description: Percentual ou valor fixo. Padrão `PERCENTAGE`.
              enum:
                - PERCENTAGE
                - FIXED_AMOUNT
            value:
              type: number
              description: Valor do desconto.
            minimumOrderValue:
              type: number
              description: Valor mínimo do pedido.
            usageLimit:
              type: integer
              description: Limite total de usos (`0` = sem limite).
            usagePerCustomer:
              type: string
              description: Uso por cliente. Padrão `ONCE`.
              enum:
                - ONCE
                - MANY
                - FIRST_ORDER
            discountType:
              type: string
              description: Sobre o que o desconto incide. Padrão `TOTAL`.
              enum:
                - TOTAL
                - SUBTOTAL
                - DELIVERY
        options:
          type: array
          description: Opções do desconto.
          items:
            type: string
            enum:
              - CUMULATIVE_WITH_SMART
              - NON_PROMOTION_PRODUCTS
              - SUBSCRIBER

    discount:
      type: object
      properties:
        id:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        startsAt:
          type: string
          format: date-time
        endsAt:
          type: string
          format: date-time
          description: Omitido quando o desconto não tem fim de vigência.
        type:
          type: string
          enum:
            - COUPON
            - SMART
        code:
          type: string
          description: Código do cupom. Presente apenas em `COUPON`.
        name:
          type: string
          description: Nome do desconto. Presente apenas em `SMART`.
        status:
          type: string
          description: Situação da vigência.
          enum:
            - ACTIVE
            - SCHEDULED
            - OVERDUE
        rules:
          type: object
          properties:
            valueType:
              type: string
              enum:
                - PERCENTAGE
                - FIXED_AMOUNT
            value:
              type: number
            minimumOrderValue:
              type: number
            usageLimit:
              type: integer
            usagePerCustomer:
              type: string
              enum:
                - ONCE
                - MANY
                - FIRST_ORDER
            discountType:
              type: string
              enum:
                - TOTAL
                - SUBTOTAL
                - DELIVERY
        options:
          type: array
          description: Omitido quando não há opções.
          items:
            type: string
            enum:
              - CUMULATIVE_WITH_SMART
              - NON_PROMOTION_PRODUCTS
              - SUBSCRIBER

    discountStats:
      type: object
      properties:
        id:
          type: string
          format: uuid
        totalDiscount:
          $ref: "#/components/schemas/money"
        totalOrder:
          $ref: "#/components/schemas/money"
        totalOrderAverage:
          $ref: "#/components/schemas/money"
        totalOrderCount:
          type: integer
          description: Quantidade de pedidos com o desconto.
        totalNewCustomers:
          type: integer
          description: Clientes cujo primeiro pedido na loja usou o desconto.
        totalReactivatedCustomers:
          type: integer
          description: Clientes que voltaram a comprar, após mais de 30 dias, usando o desconto.

    tabInput:
      type: object
      properties:
        name:
          type: string
          description: Nome da comanda.
        code:
          type: string
          description: Código da comanda.

    tab:
      type: object
      properties:
        id:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        name:
          type: string
        code:
          type: string
        qrcode:
          type: string
          description: Conteúdo do QR Code da comanda.
        status:
          type: string
          enum:
            - AVAILABLE
            - UNAVAILABLE
        situation:
          type: string
          enum:
            - OPENED
            - CLOSED

    place:
      type: object
      properties:
        id:
          type: string
          description: Id da mesa (QR Code ou tablet).
        name:
          type: string
        status:
          type: string
          description: Situação da mesa. `BUSY` indica mesa aberta com pedidos em andamento.
          enum:
            - OPENED
            - BUSY
            - CLOSED

    deliveryFee:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Id gerado para este cálculo.
        createdAt:
          type: string
          format: date-time
        status:
          type: string
          description: Se a coordenada está dentro da área de entrega.
          enum:
            - AVAILABLE
            - UNAVAILABLE
        distanceInMeters:
          type: integer
          description: Distância da loja até a coordenada, em metros.
        fee:
          type: string
          description: Valor da taxa em BRL, como string decimal. Omitido quando `status` é `UNAVAILABLE`.
          example: "7.5"

    actionResult:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Id do recurso afetado.

    Merchant:
      type: object
      title: Merchant
      properties:
        id:
          type: string
          format: uuid
          description: Id da loja.
          example: dbc7e35a-c936-4665-9e13-eb55eb8b6824
        lastUpdate:
          type: string
          format: date-time
          description: Data e hora da última alteração da loja.
          example: "2021-05-27T20:45:10-03:00"
        ttl:
          type: integer
          description: Tempo de validade dos dados, em segundos. Na leitura, sempre 3600.
          example: 3600
        status:
          type: string
          description: Indica se a loja está aberta (`AVAILABLE`) ou fechada (`UNAVAILABLE`).
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE
        basicInfo:
          $ref: "#/components/schemas/BasicInfo"
        services:
          type: array
          description: Serviços da loja (entrega e retirada).
          items:
            $ref: "#/components/schemas/Service"
        paymentMethods:
          type: array
          description: Formas de pagamento. Omitido quando a loja não tem complementos cadastrados.
          items:
            $ref: "#/components/schemas/PaymentMethod"
        options:
          type: array
          description: Complementos. Omitido quando a loja não tem complementos.
          items:
            $ref: "#/components/schemas/Option"
        optionGroups:
          type: array
          description: Grupos de complementos. Omitido quando a loja não tem grupos.
          items:
            $ref: "#/components/schemas/OptionGroup"
        categories:
          type: array
          description: Categorias. Omitido quando a loja não tem categorias.
          items:
            $ref: "#/components/schemas/Category"
        items:
          type: array
          description: Itens do cardápio. Omitido quando a loja não tem itens.
          items:
            $ref: "#/components/schemas/Item"

    MerchantUpdate:
      type: object
      discriminator:
        propertyName: entityType
        mapping:
          SERVICE: "#/components/schemas/ServiceUpdate"
          OPTION: "#/components/schemas/OptionUpdate"
          OPTION_GROUP: "#/components/schemas/OptionGroupUpdate"
          CATEGORY: "#/components/schemas/CategoryUpdate"
          ITEM: "#/components/schemas/ItemUpdate"
          PAYMENT_METHOD: "#/components/schemas/PaymentMethodUpdate"
      properties:
        merchantStatus:
          type: string
          description: Abre (`AVAILABLE`) ou fecha (`UNAVAILABLE`) a loja.
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE
        entityType:
          type: string
          description: Tipo das entidades enviadas em `updatedObjects`.
          enum:
            - SERVICE
            - OPTION
            - OPTION_GROUP
            - CATEGORY
            - ITEM
            - PAYMENT_METHOD

    MerchantUpsert:
      type: object
      discriminator:
        propertyName: entityType
        mapping:
          SERVICE: "#/components/schemas/ServiceUpsert"
          OPTION: "#/components/schemas/OptionUpsert"
          OPTION_GROUP: "#/components/schemas/OptionGroupUpsert"
          CATEGORY: "#/components/schemas/CategoryUpsert"
          ITEM: "#/components/schemas/ItemUpsert"
          PAYMENT_METHOD: "#/components/schemas/PaymentMethodUpsert"
      properties:
        merchantStatus:
          type: string
          description: Abre (`AVAILABLE`) ou fecha (`UNAVAILABLE`) a loja.
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE
        entityType:
          type: string
          description: Tipo das entidades enviadas em `upsertObjects`.
          enum:
            - SERVICE
            - OPTION
            - OPTION_GROUP
            - CATEGORY
            - ITEM
            - PAYMENT_METHOD

    BasicInfo:
      type: object
      title: BasicInfo
      description: Informações básicas da loja.
      required: ["name", "document", "corporateName"]
      properties:
        name:
          type: string
          description: Nome público da loja.
          maxLength: 500
          example: Pizzaria da Praça
        document:
          type: string
          description: CNPJ da loja, apenas dígitos.
          example: "22815773000169"
        corporateName:
          type: string
          description: Razão social.
          maxLength: 500
          example: Pizzaria da Praça Ltda.
        description:
          type: string
          description: Descrição da loja. Omitida quando vazia.
          example: Pizzaria especializada em massa de fermentação natural.
        address:
          $ref: "#/components/schemas/Address"
        contactEmails:
          type: array
          description: E-mails de contato.
          items:
            type: string
          example: ["contato@pizzariadapraca.com.br"]
        contactPhones:
          description: >-
            Telefone de contato. Na leitura vem como objeto; no envio em `merchantForce`, deve ser uma lista de
            objetos.
          oneOf:
            - $ref: "#/components/schemas/ContactPhones"
            - type: array
              items:
                $ref: "#/components/schemas/ContactPhones"
        createdAt:
          type: string
          format: date-time
          description: Data e hora de cadastro da loja.

    ServiceUpdate:
      description: Atualização de objetos `Service`.
      allOf:
        - $ref: "#/components/schemas/MerchantUpdate"
        - type: object
          properties:
            updatedObjects:
              description: Objetos `Service` atualizados.
              type: array
              items:
                $ref: "#/components/schemas/Service"

    OptionUpdate:
      description: Atualização de objetos `Option`. Apenas `id` é obrigatório.
      allOf:
        - $ref: "#/components/schemas/MerchantUpdate"
        - type: object
          properties:
            updatedObjects:
              description: Objetos `Option` atualizados.
              type: array
              items:
                $ref: "#/components/schemas/Option"

    OptionGroupUpdate:
      description: Atualização de objetos `OptionGroup`. Apenas `id` é obrigatório.
      allOf:
        - $ref: "#/components/schemas/MerchantUpdate"
        - type: object
          properties:
            updatedObjects:
              description: Objetos `OptionGroup` atualizados.
              type: array
              items:
                $ref: "#/components/schemas/OptionGroup"

    CategoryUpdate:
      description: Atualização de objetos `Category`. Apenas `id` é obrigatório.
      allOf:
        - $ref: "#/components/schemas/MerchantUpdate"
        - type: object
          properties:
            updatedObjects:
              description: Objetos `Category` atualizados.
              type: array
              items:
                $ref: "#/components/schemas/Category"

    ItemUpdate:
      description: Atualização de objetos `Item`. Apenas `id` é obrigatório.
      allOf:
        - $ref: "#/components/schemas/MerchantUpdate"
        - type: object
          properties:
            updatedObjects:
              description: Objetos `Item` atualizados.
              type: array
              items:
                $ref: "#/components/schemas/Item"

    PaymentMethodUpdate:
      description: Atualização de objetos `PaymentMethod`. Apenas `id` é obrigatório.
      allOf:
        - $ref: "#/components/schemas/MerchantUpdate"
        - type: object
          properties:
            updatedObjects:
              description: Objetos `PaymentMethod` atualizados.
              type: array
              items:
                $ref: "#/components/schemas/PaymentMethod"

    ServiceUpsert:
      description: Upsert de objetos `Service`.
      allOf:
        - $ref: "#/components/schemas/MerchantUpsert"
        - type: object
          properties:
            upsertObjects:
              description: Objetos `Service` a criar ou atualizar.
              type: array
              items:
                $ref: "#/components/schemas/Service"

    OptionUpsert:
      description: Upsert de objetos `Option`.
      allOf:
        - $ref: "#/components/schemas/MerchantUpsert"
        - type: object
          properties:
            upsertObjects:
              description: Objetos `Option` a criar ou atualizar.
              type: array
              items:
                $ref: "#/components/schemas/Option"

    OptionGroupUpsert:
      description: Upsert de objetos `OptionGroup`.
      allOf:
        - $ref: "#/components/schemas/MerchantUpsert"
        - type: object
          properties:
            upsertObjects:
              description: Objetos `OptionGroup` a criar ou atualizar.
              type: array
              items:
                $ref: "#/components/schemas/OptionGroup"

    CategoryUpsert:
      description: Upsert de objetos `Category`.
      allOf:
        - $ref: "#/components/schemas/MerchantUpsert"
        - type: object
          properties:
            upsertObjects:
              description: Objetos `Category` a criar ou atualizar.
              type: array
              items:
                $ref: "#/components/schemas/Category"

    ItemUpsert:
      description: Upsert de objetos `Item`.
      allOf:
        - $ref: "#/components/schemas/MerchantUpsert"
        - type: object
          properties:
            upsertObjects:
              description: Objetos `Item` a criar ou atualizar.
              type: array
              items:
                $ref: "#/components/schemas/Item"

    PaymentMethodUpsert:
      description: Upsert de objetos `PaymentMethod`.
      allOf:
        - $ref: "#/components/schemas/MerchantUpsert"
        - type: object
          properties:
            upsertObjects:
              description: Objetos `PaymentMethod` a criar ou atualizar.
              type: array
              items:
                $ref: "#/components/schemas/PaymentMethod"

    Service:
      type: object
      title: Service
      required: ["serviceType", "serviceTime"]
      properties:
        status:
          type: string
          description: Indica se o serviço está disponível.
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE
        serviceType:
          type: string
          description: |-
            Tipo de serviço oferecido:
            `DELIVERY` - pedidos entregues no endereço do cliente.
            `TAKEOUT` - pedidos retirados pelo cliente no estabelecimento.
          enum:
            - DELIVERY
            - TAKEOUT
          example: DELIVERY
        serviceTime:
          type: integer
          description: Tempo estimado do serviço, em minutos.
          example: 15

    PaymentMethod:
      type: object
      title: PaymentMethod
      required: ["id", "name", "mode"]
      properties:
        id:
          type: string
          format: uuid
          description: Id da forma de pagamento.
          example: 92fad022-2c28-4239-a026-989f5b555cb7
        index:
          type: integer
          description: Posição de exibição.
          example: 1
        name:
          type: string
          description: Nome da forma de pagamento.
          maxLength: 150
          example: Visa - Crédito
        externalCode:
          type: string
          description: Código externo (normalmente o código da forma de pagamento no sistema da loja).
          example: "13"
        status:
          type: string
          description: Indica se a forma de pagamento está disponível.
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE
        mode:
          type: string
          description: Modalidade de pagamento.
          enum:
            - CASH
            - CREDIT
            - DEBIT
            - PIX
            - MEAL_VOUCHER
            - FOOD_VOUCHER
            - OTHER
          example: CASH

    Option:
      type: object
      title: Option
      required: ["id", "name"]
      properties:
        id:
          type: string
          format: uuid
          description: Id do complemento.
          example: e5232f14-430c-4a94-8ff6-289d5a16a87a
        name:
          type: string
          description: Nome do complemento.
          example: Abacaxi
        description:
          type: string
          description: Descrição do complemento.
          example: Fatias de abacaxi fresco
        externalCode:
          type: string
          description: Código externo do complemento.
        status:
          type: string
          description: Indica se o complemento está disponível.
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE
        image:
          $ref: "#/components/schemas/Image"

    OptionGroup:
      type: object
      title: Option Group
      required: ["id", "name"]
      properties:
        id:
          type: string
          format: uuid
          description: Id do grupo de complementos.
          example: fe67e551-f42f-499a-8afb-0ed893c71fa3
        name:
          type: string
          description: Nome do grupo de complementos.
          maxLength: 150
          example: Escolha o sabor da pizza
        externalCode:
          type: string
          description: Código externo (normalmente o código do grupo no sistema da loja).
          example: "12"
        status:
          type: string
          description: Indica se o grupo está disponível.
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE
        optionIds:
          type: array
          description: Ids dos complementos (`Option`) que pertencem a este grupo.
          items:
            type: string
            format: uuid
            example: e5232f14-430c-4a94-8ff6-289d5a16a87a

    Category:
      type: object
      title: Category
      required: ["id", "name"]
      properties:
        id:
          type: string
          format: uuid
          description: Id da categoria.
          example: 92fad022-2c28-4239-a026-989f5b555cb7
        index:
          type: integer
          description: Posição de exibição.
          example: 0
        name:
          type: string
          description: Nome da categoria.
          maxLength: 150
          example: Pizzas salgadas
        description:
          type: string
          description: Descrição da categoria.
          example: Sabores de pizzas salgadas.
        externalCode:
          type: string
          description: Código externo (normalmente o código da categoria no sistema da loja).
          example: "13"
        status:
          type: string
          description: Indica se a categoria está disponível.
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE

    Item:
      type: object
      title: Item
      required: ["id", "name", "menu", "price", "categoryId"]
      properties:
        id:
          type: string
          format: uuid
          description: Id do item.
          example: 732bd31e-77fc-47ee-88ee-a0437f97b198
        index:
          type: integer
          description: Posição de exibição.
          example: 0
        name:
          type: string
          description: Nome do item.
          maxLength: 150
          example: Pizza de calabresa
        description:
          type: string
          description: Descrição do item.
          example: Calabresa fatiada, cebola e azeitonas.
        externalCode:
          type: string
          description: Código externo (normalmente o código do item no sistema da loja).
          example: "233467"
        status:
          type: string
          description: Indica se o item está disponível.
          enum:
            - AVAILABLE
            - UNAVAILABLE
          example: AVAILABLE
        ean:
          type: string
          description: Código EAN do produto.
          example: "7896005202074"
        menu:
          type: array
          items:
            type: string
            enum:
              - DELIVERY
              - TAKEOUT
              - DELIVERY_TAKEOUT
              - INDOOR
          description: |-
            Cardápios em que o item é vendido:
            `DELIVERY` - cardápio de entrega
            `TAKEOUT` - cardápio de retirada
            `DELIVERY_TAKEOUT` - alias legado, equivale a `DELIVERY` + `TAKEOUT`
            `INDOOR` - cardápio de consumo no local

            Na leitura, itens disponíveis para entrega e retirada trazem `DELIVERY_TAKEOUT` junto dos valores
            separados, por compatibilidade.
        price:
          $ref: "#/components/schemas/ItemPrice"
        categoryId:
          type: string
          format: uuid
          description: Id da categoria do item.
          example: 92fad022-2c28-4239-a026-989f5b555cb7
        image:
          $ref: "#/components/schemas/Image"
        modifiers:
          type: array
          description: Etapas de personalização do item (por exemplo, escolha de sabores).
          items:
            type: object
            title: Modifier
            required: ["id", "name"]
            properties:
              id:
                type: string
                format: uuid
                description: Id da etapa.
                example: 732bd31e-77fc-47ee-88ee-a0437f97b198
              index:
                type: integer
                description: Posição de exibição.
                example: 0
              name:
                type: string
                maxLength: 150
                example: Escolha os sabores
              externalCode:
                type: string
                description: Código externo da etapa.
              status:
                type: string
                description: Indica se a etapa está disponível.
                enum:
                  - AVAILABLE
                  - UNAVAILABLE
                example: AVAILABLE
              rule:
                type: string
                description: |-
                  Regra de cálculo do preço dos complementos:
                  `ADDITION` - soma os preços de todos os complementos escolhidos.
                  `APPORTIONMENT` - soma os preços dos complementos escolhidos e divide pela quantidade escolhida.
                  `HIGHEST` - considera o complemento de maior preço.
                enum:
                  - ADDITION
                  - APPORTIONMENT
                  - HIGHEST
                example: ADDITION
              minPermitted:
                type: integer
                description: Quantidade mínima de complementos a escolher.
                example: 1
              maxPermitted:
                type: integer
                description: Quantidade máxima de complementos a escolher (`0` = sem limite).
                example: 4
              optionGroups:
                type: array
                items:
                  type: object
                  title: Option Group
                  required: ["optionGroupId"]
                  properties:
                    optionGroupId:
                      type: string
                      format: uuid
                      description: Id do grupo de complementos.
                      example: 732bd31e-77fc-47ee-88ee-a0437f97b198
                    index:
                      type: integer
                      description: Posição de exibição.
                      example: 0
                    options:
                      type: array
                      items:
                        type: object
                        title: Option
                        required: ["optionId"]
                        properties:
                          optionId:
                            type: string
                            format: uuid
                            description: Id do complemento.
                            example: 732bd31e-77fc-47ee-88ee-a0437f97b198
                          index:
                            type: integer
                            description: Posição de exibição.
                            example: 0
                          status:
                            type: string
                            description: Indica se o complemento está disponível neste item.
                            enum:
                              - AVAILABLE
                              - UNAVAILABLE
                            example: AVAILABLE
                          price:
                            $ref: "#/components/schemas/ItemPrice"

    Address:
      type: object
      title: Address
      description: Endereço da loja.
      required:
        - state
        - city
        - district
        - street
        - number
        - postalCode
      properties:
        country:
          type: string
          description: Sigla do país (ISO 3166-1 alfa-2).
          example: BR
        state:
          type: string
          description: Sigla do estado.
          example: SP
        city:
          type: string
          description: Cidade.
          example: São Paulo
        district:
          type: string
          description: Bairro.
          example: Moema
        street:
          type: string
          description: Logradouro.
          example: Avenida Ibirapuera
        number:
          type: string
          description: Número.
          example: "100"
        postalCode:
          type: string
          description: CEP.
          example: 04029-000
        complement:
          type: string
          description: Complemento. Omitido quando vazio.
          example: Loja 2
        reference:
          type: string
          description: Ponto de referência. Omitido quando vazio.
          example: Em frente à praça
        formattedAddress:
          type: string
          description: Endereço completo formatado.
        coordinates:
          type: object
          properties:
            latitude:
              type: number
              description: Latitude em graus, entre -90 e 90.
              example: -23.54809
            longitude:
              type: number
              description: Longitude em graus, entre -180 e 180.
              example: -46.63638

    ContactPhones:
      type: object
      title: Contact Phones
      properties:
        commercialNumber:
          type: string
          description: Telefone comercial da loja, no formato E.164 sem formatação.
          example: "5511999999999"

    ItemPrice:
      type: object
      title: Item Price
      required: ["value", "originalValue", "currency"]
      properties:
        value:
          type: number
          description: Preço atual. Até 4 casas decimais.
          example: 50
        originalValue:
          type: number
          description: Preço original (antes de promoção). Até 4 casas decimais.
          example: 50
        currency:
          type: string
          description: Moeda (código ISO 4217).
          enum:
            - BRL
          example: BRL

    Image:
      description: Imagem.
      type: object
      required: ["url", "checksum"]
      properties:
        url:
          type: string
          format: uri
          description: >-
            URL HTTPS da imagem. Baixe e armazene a imagem do seu lado: a URL pode deixar de ser válida depois
            de algum tempo.
          example: "https://pizzariadapraca.com.br/imagem.jpg"
        checksum:
          type: string
          description: Checksum do arquivo. Use para detectar mudanças na imagem.
          example: 96b41025

    Error:
      type: object
      required: ["title", "status"]
      properties:
        status:
          type: string
          description: Código HTTP da resposta, como string.
          example: "404"
        title:
          description: >-
            Descrição do problema. Em erros de validação pode vir como objeto (campo → lista de mensagens) ou
            como lista.
          oneOf:
            - type: string
            - type: object
            - type: array
              items:
                type: string
          example: Record not found

    UnauthorizedError:
      type: object
      properties:
        title:
          type: string
          example: Unauthorized
        status:
          type: integer
          example: 401

  responses:
    ActionAccepted:
      description: Ação aceita.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/actionResult"
    ActionOk:
      description: Ação processada.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/actionResult"
    PlaceActionAccepted:
      description: Ação aceita.
      content:
        application/json:
          schema:
            type: object
            properties:
              id:
                type: string
                description: Id da mesa.
    BadRequestCursor:
      description: Os cursores `next` e `previous` foram informados juntos.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Token ausente, inválido, expirado ou revogado.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/UnauthorizedError"
    NotFound:
      description: Recurso não encontrado (ou loja não autorizada para o aplicativo).
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            status: "404"
            title: Record not found
    NotAcceptable:
      description: Parâmetros de filtro inválidos.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    DiscountNotHired:
      description: >-
        A loja não contratou o recurso de descontos (`growth_discount_not_hired`) ou o token não tem o escopo
        `od.all` (neste caso, sem corpo).
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            status: "403"
            title: growth_discount_not_hired
    MalformedJson:
      description: O corpo da requisição não é um JSON válido, ou o token não tem o escopo `od.all` (sem corpo).
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    UnprocessableEntity:
      description: A transição não é permitida no estado atual do pedido.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    ValidationFailed:
      description: Falha de validação. `title` traz os erros por campo.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    CatalogUnprocessable:
      description: >-
        O corpo não respeita o schema (`title` traz a lista de erros), `entityType` não é permitido
        (`entity_type_unallowed`), a lista de objetos está vazia (`objects_empty`) ou houve erro ao gravar.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Token de acesso opaco emitido pela API de autenticação (`POST /authentication/v1/oauth/token`).
