openapi: 3.0.3

info:
  version: v2
  title: API de Parceiros DeliveryVip
  description: >-
    A API de Parceiros da DeliveryVip permite que parceiros e revendas gerenciem as lojas
    (merchants) e as revendas da sua carteira: cadastro, consulta, membros, assinaturas,
    recursos contratados, aplicações autorizadas, planos e faturas.


    Todas as rotas exigem um access token OAuth 2.0 com o escopo `dv.partner`, enviado no
    cabeçalho `Authorization: Bearer <token>`. O token dá acesso aos parceiros autorizados
    para a aplicação. O cabeçalho opcional `x-partners` (lista de UUIDs separados por
    vírgula) restringe a requisição a um subconjunto desses parceiros; um UUID fora da
    autorização do token resulta em `403`.


    Erros seguem o formato `{"status": "<código HTTP>", "title": <mensagem>}`, em que
    `title` é um texto ou, em erros de validação, um objeto com as mensagens por campo.

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

security:
  - bearerAuth: []

tags:
  - name: Signup
    description: >-
      Cadastro público de loja, consumido por uma landing page e não pelo backend do parceiro.
  - name: Plans
    description: >-
      Planos disponíveis para as lojas do parceiro.
  - name: Invoices
    description: >-
      Faturas das lojas do parceiro.
  - name: Merchants
    description: >-
      Cadastro, listagem e consulta de lojas, vendas e faturas.
  - name: Merchants/Subscriptions
    description: >-
      Ativação, cancelamento, aviso, bloqueio e atualização da assinatura da loja.
  - name: Merchants/Members
    description: >-
      Adição, alteração e remoção de membros da loja.
  - name: Merchants/Applications
    description: >-
      Autorização e revogação de aplicações na loja.
  - name: Merchants/Features
    description: >-
      Contratação e cancelamento de recursos adicionais da loja.
  - name: Resales
    description: >-
      Cadastro, listagem e consulta de revendas e suas faturas.
  - name: Resales/Subscriptions
    description: >-
      Ativação, cancelamento, aviso, bloqueio e atualização da assinatura da revenda.
  - name: Resales/Members
    description: >-
      Adição, alteração e remoção de membros da revenda.
  - name: Resales/Applications
    description: >-
      Autorização e revogação de aplicações na revenda.

paths:
  /partner/v2/{partnerId}/plans:
    get:
      tags:
        - Plans
      summary: Listar planos
      description: >-
        Lista os planos do parceiro, em qualquer status. Quando `partnerId` é uma revenda,
        retorna apenas os planos com visibilidade `PUBLIC` e `RESALE`; quando é um parceiro,
        retorna também os `DIRECT_MERCHANT`. Planos `PRIVATE` nunca são retornados.
      parameters:
        - $ref: "#/components/parameters/partnerId"
      responses:
        "200":
          description: Lista de planos.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/plan"
        "204":
          description: Nenhum plano encontrado.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"

  /partner/v2/{partnerId}/plans/{planId}:
    get:
      tags:
        - Plans
      summary: Consultar plano
      description: >-
        Retorna um plano do parceiro. Segue as mesmas regras de visibilidade da listagem.
      parameters:
        - $ref: "#/components/parameters/partnerId"
        - in: path
          name: planId
          description: UUID do plano.
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Plano encontrado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/plan"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

  /partner/v2/{partnerId}/signup:
    post:
      tags:
        - Signup
      summary: Cadastrar loja por página pública
      description: >-
        Cria uma loja e a conta do seu dono a partir de uma landing page pública, em que
        quem preenche o formulário é um visitante anônimo e não o backend do parceiro.


        A resposta é propositalmente a mesma esteja o e-mail cadastrado ou não, para que o
        endpoint não sirva para descobrir quais endereços já têm conta. O que muda é o que
        acontece por trás:


        Quando o e-mail está livre, a conta e a loja são criadas e `entryUrl` é retornado:
        um link de uso único, válido por 5 minutos, que autentica o novo dono. Quando o
        e-mail já pertence a uma conta, nada é criado, nenhum acesso é concedido e
        `entryUrl` não vem na resposta: um e-mail é enviado ao dono real do endereço, e só
        ele pode dar continuidade ao cadastro. Uma conta existente nunca é vinculada a uma
        loja nova sem prova de titularidade.
      parameters:
        - $ref: "#/components/parameters/partnerId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - user
                - store
              properties:
                user:
                  type: object
                  description: Dados do dono da loja.
                  required:
                    - name
                    - email
                    - password
                  properties:
                    name:
                      type: string
                      description: Nome do dono.
                    email:
                      type: string
                      format: email
                      description: E-mail de acesso do dono.
                    password:
                      type: string
                      format: password
                      description: >-
                        Senha escolhida pelo lead. É com ela que ele entra normalmente
                        depois, sem que nenhum token de acesso precise circular por e-mail.
                    phone:
                      type: object
                      properties:
                        number:
                          type: string
                          description: Telefone do dono.
                store:
                  type: object
                  description: Dados da loja.
                  required:
                    - name
                    - identifier
                    - address
                  properties:
                    name:
                      type: string
                      description: Nome fantasia.
                    corporateName:
                      type: string
                      description: >-
                        Razão social. Opcional; quando omitida, usa o nome fantasia.
                    identifier:
                      type: string
                      description: >-
                        CNPJ ou CPF (somente dígitos). Ambos são aceitos e validados.
                    email:
                      type: string
                      format: email
                      description: >-
                        E-mail da loja. Opcional; quando omitido, usa o e-mail do dono.
                    address:
                      $ref: "#/components/schemas/addressInput"
            example:
              user:
                name: Maria Souza
                email: maria@pizzariadamaria.com.br
                password: s3nh4-f0rte
                phone:
                  number: "11987654321"
              store:
                name: Pizzaria da Maria
                corporateName: Pizzaria da Maria LTDA
                identifier: "12345678000195"
                address:
                  postalCode: "01310100"
                  street: Avenida Paulista
                  number: "1000"
                  district: Bela Vista
                  city: São Paulo
                  state: SP
      responses:
        "201":
          description: >-
            Recebido. Retornado nos dois cenários: `entryUrl` e `merchantId` só vêm quando a
            conta foi de fato criada.
          content:
            application/json:
              schema:
                type: object
                required:
                  - message
                properties:
                  message:
                    type: string
                    description: Mensagem de confirmação do recebimento.
                  entryUrl:
                    type: string
                    format: uri
                    description: >-
                      Link de entrada de uso único, válido por 5 minutos. Ausente quando o
                      e-mail já pertencia a uma conta.
                  merchantId:
                    type: string
                    format: uuid
                    description: UUID da loja criada.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: >-
            Proibido. Retornado quando o `partnerId` não é autorizado para o token ou quando
            o parceiro não tem domínio de painel configurado ("partner must be setup a domain
            to user access").
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/error"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/{partnerId}/merchants:
    post:
      tags:
        - Merchants
      summary: Criar loja
      description: >-
        Cria uma loja vinculada ao parceiro ou à revenda informada em `partnerId`. Os campos
        podem ser enviados na raiz do corpo ou dentro de um objeto `merchant`.
      parameters:
        - $ref: "#/components/parameters/partnerId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - corporateName
                - identifier
                - email
                - personResponsible
                - address
              properties:
                name:
                  type: string
                  description: Nome fantasia.
                corporateName:
                  type: string
                  description: Razão social.
                identifier:
                  type: string
                  description: >-
                    CNPJ ou CPF (somente dígitos). Ambos são aceitos e validados.
                email:
                  type: string
                  format: email
                  description: E-mail da loja.
                personResponsible:
                  type: object
                  description: Responsável pela loja.
                  required:
                    - name
                    - email
                    - phone
                  properties:
                    name:
                      type: string
                      description: Nome do responsável.
                    email:
                      type: string
                      format: email
                      description: E-mail do responsável.
                    phone:
                      type: object
                      required:
                        - number
                      properties:
                        number:
                          type: string
                          description: Telefone do responsável.
                    identifier:
                      type: string
                      description: CPF do responsável.
                address:
                  $ref: "#/components/schemas/addressInput"
            example:
              name: Pizzaria da Maria
              corporateName: Pizzaria da Maria LTDA
              identifier: "12345678000195"
              email: contato@pizzariadamaria.com.br
              personResponsible:
                name: Maria Souza
                email: maria@pizzariadamaria.com.br
                phone:
                  number: "11987654321"
                identifier: "12345678909"
              address:
                postalCode: "01310100"
                street: Avenida Paulista
                number: "1000"
                district: Bela Vista
                city: São Paulo
                state: SP
      responses:
        "201":
          description: Loja criada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/merchant"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/{partnerId}/merchants/invoices:
    get:
      tags:
        - Invoices
      summary: Listar faturas das lojas diretas
      description: >-
        Lista as faturas do mês das lojas. Quando `partnerId` é um parceiro, retorna apenas
        as lojas vendidas diretamente por ele (sem revenda); quando é uma revenda, retorna
        as lojas da revenda. Os blocos de preço `RECEIVABLE` só aparecem quando o parceiro
        tem tabela de preços própria.
      parameters:
        - $ref: "#/components/parameters/partnerId"
        - $ref: "#/components/parameters/year"
        - $ref: "#/components/parameters/month"
      responses:
        "200":
          description: Lista de faturas.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/MerchantInvoiceObject"
        "204":
          description: Nenhuma fatura no período.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"

  /partner/v2/{partnerId}/resales:
    post:
      tags:
        - Resales
      summary: Criar revenda
      description: >-
        Cria uma revenda vinculada ao parceiro. Disponível apenas quando `partnerId` é um
        parceiro; uma revenda não pode criar outra revenda.
      parameters:
        - $ref: "#/components/parameters/partnerId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - corporateName
                - identifier
                - email
                - phone
                - personResponsible
                - address
              properties:
                name:
                  type: string
                  description: Nome fantasia.
                corporateName:
                  type: string
                  description: Razão social.
                identifier:
                  type: string
                  description: >-
                    CNPJ ou CPF (somente dígitos). Ambos são aceitos e validados.
                email:
                  type: string
                  format: email
                  description: E-mail da revenda.
                phone:
                  type: object
                  required:
                    - number
                  properties:
                    number:
                      type: string
                      description: Telefone da revenda.
                personResponsible:
                  type: object
                  description: Responsável pela revenda.
                  required:
                    - name
                    - email
                    - phone
                  properties:
                    name:
                      type: string
                      description: Nome do responsável.
                    email:
                      type: string
                      format: email
                      description: E-mail do responsável.
                    phone:
                      type: object
                      required:
                        - number
                      properties:
                        number:
                          type: string
                          description: Telefone do responsável.
                    document:
                      type: string
                      description: CPF do responsável.
                address:
                  $ref: "#/components/schemas/addressInput"
            example:
              name: Revenda Sul
              corporateName: Revenda Sul Tecnologia LTDA
              identifier: "98765432000110"
              email: contato@revendasul.com.br
              phone:
                number: "51987654321"
              personResponsible:
                name: João Pereira
                email: joao@revendasul.com.br
                phone:
                  number: "51987654321"
                document: "12345678909"
              address:
                postalCode: "90010000"
                street: Rua dos Andradas
                number: "500"
                district: Centro Histórico
                city: Porto Alegre
                state: RS
      responses:
        "201":
          description: Revenda criada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/resale"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: >-
            Proibido. Retornado quando `partnerId` é uma revenda ou não é autorizado para o
            token.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/error"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/{partnerId}/resales/invoices:
    get:
      tags:
        - Invoices
      summary: Listar faturas das revendas
      description: >-
        Resume, por revenda, as faturas do mês das revendas do parceiro. Faturas de lojas
        vendidas diretamente pelo parceiro não entram. Os blocos de preço `RECEIVABLE` só
        aparecem quando o parceiro tem tabela de preços própria.
      parameters:
        - $ref: "#/components/parameters/partnerId"
        - $ref: "#/components/parameters/year"
        - $ref: "#/components/parameters/month"
      responses:
        "200":
          description: Resumo das faturas por revenda.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ResaleInvoiceObject"
        "204":
          description: Nenhuma fatura no período.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: >-
            Proibido. Retornado quando `partnerId` é uma revenda ou não é autorizado para o
            token.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/error"

  /partner/v2/{partnerId}/invoices:
    get:
      tags:
        - Invoices
      summary: Listar faturas
      description: >-
        Lista as faturas do mês de todas as lojas do parceiro (diretas e de revendas) ou, quando
        `partnerId` é uma revenda, das lojas da revenda. Para revendas, `totalPrice` só vem
        quando a revenda tem tabela de preços própria.
      parameters:
        - $ref: "#/components/parameters/partnerId"
        - $ref: "#/components/parameters/year"
        - $ref: "#/components/parameters/month"
      responses:
        "200":
          description: Lista de faturas.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/invoice"
        "204":
          description: Nenhuma fatura no período.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"

  /partner/v2/merchants:
    get:
      tags:
        - Merchants
      summary: Listar lojas
      description: >-
        Lista as lojas dos parceiros e revendas autorizados para o token.
      parameters:
        - $ref: "#/components/parameters/subscriptionStatus"
        - $ref: "#/components/parameters/subscriptionAgreementCode"
        - $ref: "#/components/parameters/merchantIdentifier"
      responses:
        "200":
          description: Lista de lojas.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/merchant"
        "204":
          description: Nenhuma loja encontrada.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: >-
            Proibido. Retornado quando `subscriptionStatus` tem um valor inválido ("Invalid
            subscription status") ou quando `x-partners` é inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/error"

  /partner/v2/merchants/sales:
    get:
      tags:
        - Merchants
      summary: Listar vendas das lojas
      description: >-
        Retorna, por loja, a quantidade e o total de pedidos do mês.
      parameters:
        - $ref: "#/components/parameters/subscriptionStatus"
        - $ref: "#/components/parameters/subscriptionAgreementCode"
        - $ref: "#/components/parameters/merchantIdentifier"
        - $ref: "#/components/parameters/year"
        - $ref: "#/components/parameters/month"
      responses:
        "200":
          description: Vendas por loja.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/sale"
        "204":
          description: Nenhuma loja encontrada.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: >-
            Proibido. Retornado quando `subscriptionStatus` tem um valor inválido ("Invalid
            subscription status") ou quando `x-partners` é inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/error"

  /partner/v2/merchants/invoices:
    get:
      tags:
        - Merchants
      summary: Listar faturas das lojas (obsoleto)
      deprecated: true
      description: >-
        Obsoleto: use `GET /partner/v2/{partnerId}/invoices` ou
        `GET /partner/v2/{partnerId}/merchants/invoices`. A rota continua respondendo e envia
        os cabeçalhos `Deprecation: true` e `Sunset` (01/07/2025).


        Lista as faturas do mês das lojas dos parceiros autorizados para o token.
      parameters:
        - $ref: "#/components/parameters/year"
        - $ref: "#/components/parameters/month"
      responses:
        "200":
          description: Lista de faturas.
          headers:
            Deprecation:
              $ref: "#/components/headers/Deprecation"
            Sunset:
              $ref: "#/components/headers/Sunset"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/invoiceMerchant"
        "204":
          description: Nenhuma fatura no período.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"

  /partner/v2/merchants/{merchantId}:
    get:
      tags:
        - Merchants
      summary: Consultar loja
      description: >-
        Retorna uma loja do parceiro ou de uma de suas revendas.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "200":
          description: Loja encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/merchant"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

  /partner/v2/merchants/{merchantId}/members:
    get:
      tags:
        - Merchants/Members
      summary: Listar membros da loja
      description: >-
        Lista os membros da loja com conta vinculada. Convites pendentes (`INVITED`) não aparecem.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "200":
          description: Lista de membros.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/member"
        "204":
          description: A loja não tem membros.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

    post:
      tags:
        - Merchants/Members
      summary: Adicionar membro à loja
      description: >-
        Adiciona um membro à loja.


        A resposta tem dois formatos. Quando o e-mail ainda não está cadastrado, a conta é
        criada e o membro volta com `status: ACTIVE`. Quando o e-mail já pertence a uma conta,
        nenhuma conta é alterada e nenhum acesso é concedido: um convite é enviado para esse
        endereço e o membro volta com `status: INVITED`, passando a `ACTIVE` só depois que o
        dono do e-mail aceitar. Contas existentes nunca são vinculadas sem prova de
        titularidade.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        $ref: "#/components/requestBodies/memberCreate"
      responses:
        "201":
          description: Membro criado ou convidado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/member"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/members/{memberId}:
    patch:
      tags:
        - Merchants/Members
      summary: Alterar membro da loja
      description: >-
        Altera o papel de um membro da loja. A rota também aceita `PUT`.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/memberId"
      requestBody:
        $ref: "#/components/requestBodies/memberUpdate"
      responses:
        "200":
          description: Membro alterado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/member"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

    delete:
      tags:
        - Merchants/Members
      summary: Remover membro da loja
      description: >-
        Remove o membro da loja ou revoga o convite pendente.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/memberId"
      responses:
        "200":
          $ref: "#/components/responses/MemberRemoved"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

  /partner/v2/merchants/{merchantId}/members/{memberId}/magic-link:
    post:
      tags:
        - Merchants/Members
      summary: Gerar magic link do membro da loja
      description: >-
        Gera um link para o membro entrar no painel sem senha. O link usa o domínio de
        painel do parceiro e expira em 6 horas.


        O link nunca substitui um segundo fator. Se a conta exige OTP por e-mail ou
        autenticação em dois fatores, abrir o link inicia esse desafio em vez de autenticar
        o usuário, e o login só é concluído depois que o código é verificado. Por padrão as
        contas exigem OTP por e-mail. O link é de uso único e é consumido mesmo quando ainda
        há um desafio pendente. Convites pendentes (`INVITED`) não têm magic link.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/memberId"
      responses:
        "201":
          $ref: "#/components/responses/MagicLink"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/MagicLinkForbidden"
        "404":
          $ref: "#/components/responses/NotFound"

  /partner/v2/merchants/{merchantId}/activate:
    post:
      tags:
        - Merchants/Subscriptions
      summary: Ativar assinatura da loja
      description: >-
        Ativa a assinatura da loja. O parceiro (e a revenda, quando houver) precisa estar com
        a assinatura ativa. Assinaturas de demonstração não podem ser ativadas.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        $ref: "#/components/requestBodies/merchantSubscription"
      responses:
        "202":
          $ref: "#/components/responses/MerchantAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/cancel:
    post:
      tags:
        - Merchants/Subscriptions
      summary: Cancelar assinatura da loja
      description: >-
        Cancela a assinatura da loja. A assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "202":
          $ref: "#/components/responses/MerchantAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/warning:
    post:
      tags:
        - Merchants/Subscriptions
      summary: Avisar loja
      description: >-
        Marca a assinatura da loja com aviso, sinalizando um possível bloqueio. A assinatura
        precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "202":
          $ref: "#/components/responses/MerchantAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/unwarning:
    post:
      tags:
        - Merchants/Subscriptions
      summary: Remover aviso da loja
      description: >-
        Remove o aviso da assinatura da loja. A assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "202":
          $ref: "#/components/responses/MerchantAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/block:
    post:
      tags:
        - Merchants/Subscriptions
      summary: Bloquear loja
      description: >-
        Bloqueia a assinatura da loja. A assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "202":
          $ref: "#/components/responses/MerchantAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/unblock:
    post:
      tags:
        - Merchants/Subscriptions
      summary: Desbloquear loja
      description: >-
        Desbloqueia a assinatura da loja. A assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      responses:
        "202":
          $ref: "#/components/responses/MerchantAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/subscription:
    put:
      tags:
        - Merchants/Subscriptions
      summary: Atualizar assinatura da loja
      description: >-
        Atualiza o código de contrato e/ou o plano da assinatura da loja, sem mudar o status.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        $ref: "#/components/requestBodies/merchantSubscription"
      responses:
        "200":
          $ref: "#/components/responses/MerchantOk"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/agreementCode:
    put:
      tags:
        - Merchants/Subscriptions
      summary: Atualizar código de contrato da loja (obsoleto)
      deprecated: true
      description: >-
        Obsoleto: use `PUT /partner/v2/merchants/{merchantId}/subscription`, que tem o mesmo
        comportamento. A rota continua respondendo e envia os cabeçalhos `Deprecation: true`
        e `Sunset` (01/07/2025).
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        $ref: "#/components/requestBodies/merchantSubscription"
      responses:
        "200":
          description: Assinatura atualizada.
          headers:
            Deprecation:
              $ref: "#/components/headers/Deprecation"
            Sunset:
              $ref: "#/components/headers/Sunset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/merchantRef"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/applications:
    post:
      tags:
        - Merchants/Applications
      summary: Autorizar aplicação na loja
      description: >-
        Autoriza uma aplicação na loja. Apenas aplicações do tipo manual podem ser
        autorizadas por esta rota.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        $ref: "#/components/requestBodies/permission"
      responses:
        "202":
          $ref: "#/components/responses/ApplicationAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ApplicationUnprocessable"

  /partner/v2/merchants/{merchantId}/applications/{applicationId}:
    delete:
      tags:
        - Merchants/Applications
      summary: Revogar aplicação da loja
      description: >-
        Revoga a autorização da aplicação na loja.
      parameters:
        - $ref: "#/components/parameters/merchantId"
        - $ref: "#/components/parameters/applicationId"
      responses:
        "202":
          $ref: "#/components/responses/ApplicationAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

  /partner/v2/merchants/{merchantId}/features/activate:
    post:
      tags:
        - Merchants/Features
      summary: Contratar recursos
      description: >-
        Contrata recursos adicionais para a loja. Cada recurso precisa existir no plano da
        assinatura; recursos já contratados são ignorados.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        $ref: "#/components/requestBodies/feature"
      responses:
        "202":
          $ref: "#/components/responses/MerchantAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "406":
          description: >-
            Não aceito. Retornado quando um `featureType` é inválido, não existe no plano ou
            está oculto, ou quando a loja não tem licença válida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/error"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/merchants/{merchantId}/features/cancel:
    post:
      tags:
        - Merchants/Features
      summary: Cancelar recursos
      description: >-
        Cancela recursos adicionais da loja. Recursos incluídos no plano não podem ser
        cancelados.
      parameters:
        - $ref: "#/components/parameters/merchantId"
      requestBody:
        $ref: "#/components/requestBodies/feature"
      responses:
        "202":
          $ref: "#/components/responses/MerchantAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "406":
          description: >-
            Não aceito. Retornado quando um `featureType` é inválido, não está contratado ou
            está incluído no plano.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/error"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales:
    get:
      tags:
        - Resales
      summary: Listar revendas
      description: >-
        Lista as revendas dos parceiros autorizados para o token.
      parameters:
        - $ref: "#/components/parameters/subscriptionStatus"
        - $ref: "#/components/parameters/subscriptionAgreementCode"
        - in: query
          name: resaleIdentifier
          description: Filtra pelo CNPJ ou CPF da revenda.
          schema:
            type: string
      responses:
        "200":
          description: Lista de revendas.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/resale"
        "204":
          description: Nenhuma revenda encontrada.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: >-
            Proibido. Retornado quando `subscriptionStatus` tem um valor inválido ("Invalid
            subscription status") ou quando `x-partners` é inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/error"

  /partner/v2/resales/invoices:
    get:
      tags:
        - Resales
      summary: Listar faturas das revendas (obsoleto)
      deprecated: true
      description: >-
        Obsoleto: use `GET /partner/v2/{partnerId}/resales/invoices`. A rota continua
        respondendo e envia os cabeçalhos `Deprecation: true` e `Sunset` (01/07/2025).


        Lista as faturas do mês das lojas vendidas por revendas dos parceiros autorizados
        para o token.
      parameters:
        - $ref: "#/components/parameters/year"
        - $ref: "#/components/parameters/month"
      responses:
        "200":
          description: Lista de faturas.
          headers:
            Deprecation:
              $ref: "#/components/headers/Deprecation"
            Sunset:
              $ref: "#/components/headers/Sunset"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/invoiceResale"
        "204":
          description: Nenhuma fatura no período.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"

  /partner/v2/resales/{resaleId}:
    get:
      tags:
        - Resales
      summary: Consultar revenda
      description: >-
        Retorna uma revenda do parceiro.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      responses:
        "200":
          description: Revenda encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/resale"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

  /partner/v2/resales/{resaleId}/members:
    get:
      tags:
        - Resales/Members
      summary: Listar membros da revenda
      description: >-
        Lista os membros da revenda com conta vinculada. Convites pendentes (`INVITED`) não aparecem.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      responses:
        "200":
          description: Lista de membros.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/member"
        "204":
          description: A revenda não tem membros.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

    post:
      tags:
        - Resales/Members
      summary: Adicionar membro à revenda
      description: >-
        Adiciona um membro à revenda.


        A resposta tem dois formatos. Quando o e-mail ainda não está cadastrado, a conta é
        criada e o membro volta com `status: ACTIVE`. Quando o e-mail já pertence a uma conta,
        nenhuma conta é alterada e nenhum acesso é concedido: um convite é enviado para esse
        endereço e o membro volta com `status: INVITED`, passando a `ACTIVE` só depois que o
        dono do e-mail aceitar. Contas existentes nunca são vinculadas sem prova de
        titularidade.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      requestBody:
        $ref: "#/components/requestBodies/memberCreate"
      responses:
        "201":
          description: Membro criado ou convidado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/member"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/members/{memberId}:
    patch:
      tags:
        - Resales/Members
      summary: Alterar membro da revenda
      description: >-
        Altera o papel de um membro da revenda. A rota também aceita `PUT`.
      parameters:
        - $ref: "#/components/parameters/resaleId"
        - $ref: "#/components/parameters/memberId"
      requestBody:
        $ref: "#/components/requestBodies/memberUpdate"
      responses:
        "200":
          description: Membro alterado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/member"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

    delete:
      tags:
        - Resales/Members
      summary: Remover membro da revenda
      description: >-
        Remove o membro da revenda ou revoga o convite pendente.
      parameters:
        - $ref: "#/components/parameters/resaleId"
        - $ref: "#/components/parameters/memberId"
      responses:
        "200":
          $ref: "#/components/responses/MemberRemoved"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

  /partner/v2/resales/{resaleId}/members/{memberId}/magic-link:
    post:
      tags:
        - Resales/Members
      summary: Gerar magic link do membro da revenda
      description: >-
        Gera um link para o membro entrar no painel sem senha. O link usa o domínio de
        painel do parceiro e expira em 6 horas.


        O link nunca substitui um segundo fator. Se a conta exige OTP por e-mail ou
        autenticação em dois fatores, abrir o link inicia esse desafio em vez de autenticar
        o usuário, e o login só é concluído depois que o código é verificado. Por padrão as
        contas exigem OTP por e-mail. O link é de uso único e é consumido mesmo quando ainda
        há um desafio pendente. Convites pendentes (`INVITED`) não têm magic link.
      parameters:
        - $ref: "#/components/parameters/resaleId"
        - $ref: "#/components/parameters/memberId"
      responses:
        "201":
          $ref: "#/components/responses/MagicLink"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/MagicLinkForbidden"
        "404":
          $ref: "#/components/responses/NotFound"

  /partner/v2/resales/{resaleId}/activate:
    post:
      tags:
        - Resales/Subscriptions
      summary: Ativar assinatura da revenda
      description: >-
        Ativa a assinatura da revenda. Assinaturas de demonstração não podem ser ativadas.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      requestBody:
        $ref: "#/components/requestBodies/resaleSubscription"
      responses:
        "202":
          $ref: "#/components/responses/ResaleAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/cancel:
    post:
      tags:
        - Resales/Subscriptions
      summary: Cancelar assinatura da revenda
      description: >-
        Cancela a assinatura da revenda. A assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      responses:
        "202":
          $ref: "#/components/responses/ResaleAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/warning:
    post:
      tags:
        - Resales/Subscriptions
      summary: Avisar revenda
      description: >-
        Marca a assinatura da revenda com aviso, sinalizando um possível bloqueio. A
        assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      responses:
        "202":
          $ref: "#/components/responses/ResaleAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/unwarning:
    post:
      tags:
        - Resales/Subscriptions
      summary: Remover aviso da revenda
      description: >-
        Remove o aviso da assinatura da revenda. A assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      responses:
        "202":
          $ref: "#/components/responses/ResaleAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/block:
    post:
      tags:
        - Resales/Subscriptions
      summary: Bloquear revenda
      description: >-
        Bloqueia a assinatura da revenda. A assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      responses:
        "202":
          $ref: "#/components/responses/ResaleAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/unblock:
    post:
      tags:
        - Resales/Subscriptions
      summary: Desbloquear revenda
      description: >-
        Desbloqueia a assinatura da revenda. A assinatura precisa estar ativa.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      responses:
        "202":
          $ref: "#/components/responses/ResaleAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/subscription:
    put:
      tags:
        - Resales/Subscriptions
      summary: Atualizar assinatura da revenda
      description: >-
        Atualiza o código de contrato da assinatura da revenda, sem mudar o status.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      requestBody:
        $ref: "#/components/requestBodies/resaleSubscription"
      responses:
        "200":
          $ref: "#/components/responses/ResaleOk"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/agreementCode:
    put:
      tags:
        - Resales/Subscriptions
      summary: Atualizar código de contrato da revenda (obsoleto)
      deprecated: true
      description: >-
        Obsoleto: use `PUT /partner/v2/resales/{resaleId}/subscription`, que tem o mesmo
        comportamento. A rota continua respondendo e envia os cabeçalhos `Deprecation: true`
        e `Sunset` (01/07/2025).
      parameters:
        - $ref: "#/components/parameters/resaleId"
      requestBody:
        $ref: "#/components/requestBodies/resaleSubscription"
      responses:
        "200":
          description: Assinatura atualizada.
          headers:
            Deprecation:
              $ref: "#/components/headers/Deprecation"
            Sunset:
              $ref: "#/components/headers/Sunset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/resaleRef"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /partner/v2/resales/{resaleId}/applications:
    post:
      tags:
        - Resales/Applications
      summary: Autorizar aplicação na revenda
      description: >-
        Autoriza uma aplicação na revenda. Apenas aplicações do tipo manual podem ser
        autorizadas por esta rota.
      parameters:
        - $ref: "#/components/parameters/resaleId"
      requestBody:
        $ref: "#/components/requestBodies/permission"
      responses:
        "202":
          $ref: "#/components/responses/ApplicationAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/ApplicationUnprocessable"

  /partner/v2/resales/{resaleId}/applications/{applicationId}:
    delete:
      tags:
        - Resales/Applications
      summary: Revogar aplicação da revenda
      description: >-
        Revoga a autorização da aplicação na revenda.
      parameters:
        - $ref: "#/components/parameters/resaleId"
        - $ref: "#/components/parameters/applicationId"
      responses:
        "202":
          $ref: "#/components/responses/ApplicationAccepted"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"

components:
  parameters:
    partnerId:
      in: path
      name: partnerId
      description: UUID do parceiro ou da revenda.
      required: true
      schema:
        type: string
        format: uuid
    merchantId:
      in: path
      name: merchantId
      description: UUID da loja.
      required: true
      schema:
        type: string
        format: uuid
    resaleId:
      in: path
      name: resaleId
      description: UUID da revenda.
      required: true
      schema:
        type: string
        format: uuid
    memberId:
      in: path
      name: memberId
      description: UUID do membro.
      required: true
      schema:
        type: string
        format: uuid
    applicationId:
      in: path
      name: applicationId
      description: UUID da aplicação.
      required: true
      schema:
        type: string
        format: uuid
    year:
      in: query
      name: year
      description: Ano de referência. Padrão é o ano corrente.
      schema:
        type: integer
        example: 2026
    month:
      in: query
      name: month
      description: Mês de referência (1 a 12). Padrão é o mês corrente.
      schema:
        type: integer
        minimum: 1
        maximum: 12
        example: 10
    subscriptionStatus:
      in: query
      name: subscriptionStatus[]
      description: >-
        Filtra pelo status da assinatura. Aceita vários valores; maiúsculas e minúsculas
        são equivalentes.
      schema:
        type: array
        items:
          type: string
          enum:
            - TRIAL
            - DEMO
            - TRIAL_EXPIRED
            - ACTIVATED
            - CANCELLED
      style: form
      explode: true
    subscriptionAgreementCode:
      in: query
      name: subscriptionAgreementCode
      description: Filtra pelo código de contrato da assinatura.
      schema:
        type: string
    merchantIdentifier:
      in: query
      name: merchantIdentifier
      description: Filtra pelo CNPJ ou CPF da loja.
      schema:
        type: string

  headers:
    Deprecation:
      description: Sempre `true`, indicando que a rota está obsoleta.
      schema:
        type: string
        example: "true"
    Sunset:
      description: Data a partir da qual a rota pode deixar de existir (formato HTTP-date).
      schema:
        type: string
        example: Tue, 01 Jul 2025 00:00:00 GMT

  requestBodies:
    memberCreate:
      required: true
      content:
        application/json:
          schema:
            type: object
            required:
              - member
              - user
            properties:
              member:
                type: object
                required:
                  - role
                properties:
                  role:
                    $ref: "#/components/schemas/memberRoleInput"
              user:
                type: object
                required:
                  - name
                  - email
                properties:
                  name:
                    type: string
                    description: Nome do usuário.
                  email:
                    type: string
                    format: email
                    description: E-mail do usuário.
          example:
            member:
              role: manager
            user:
              name: Ana Lima
              email: ana@pizzariadamaria.com.br
    memberUpdate:
      required: true
      content:
        application/json:
          schema:
            type: object
            required:
              - member
            properties:
              member:
                type: object
                required:
                  - role
                properties:
                  role:
                    $ref: "#/components/schemas/memberRoleInput"
          example:
            member:
              role: operator
    merchantSubscription:
      required: false
      content:
        application/json:
          schema:
            type: object
            properties:
              subscription:
                type: object
                properties:
                  agreementCode:
                    type: string
                    nullable: true
                    description: >-
                      Código de contrato. Omita (ou envie `null`) para manter o código atual;
                      envie string vazia para apagá-lo.
                  planId:
                    type: string
                    format: uuid
                    description: >-
                      UUID do plano. Precisa ser um plano disponível do parceiro com
                      visibilidade compatível com a loja. Omita para manter o plano atual.
    resaleSubscription:
      required: false
      content:
        application/json:
          schema:
            type: object
            properties:
              subscription:
                type: object
                properties:
                  agreementCode:
                    type: string
                    nullable: true
                    description: >-
                      Código de contrato. Omita (ou envie `null`) para manter o código atual;
                      envie string vazia para apagá-lo.
    permission:
      required: true
      content:
        application/json:
          schema:
            type: object
            required:
              - permission
            properties:
              permission:
                type: object
                required:
                  - applicationId
                properties:
                  applicationId:
                    type: string
                    format: uuid
                    description: UUID da aplicação a autorizar.
    feature:
      required: true
      content:
        application/json:
          schema:
            type: object
            required:
              - feature
            properties:
              feature:
                type: object
                required:
                  - featureTypes
                properties:
                  featureTypes:
                    type: array
                    minItems: 1
                    description: Recursos a contratar ou cancelar.
                    items:
                      $ref: "#/components/schemas/merchantFeatureType"
          example:
            feature:
              featureTypes:
                - DELIVERYBOT_NOTIFICATION
                - INDOOR_QRCODE

  responses:
    Unauthorized:
      description: Token ausente, inválido ou expirado.
      content:
        application/json:
          schema:
            type: object
            properties:
              title:
                type: string
                example: Unauthorized
              status:
                type: integer
                example: 401
    Forbidden:
      description: >-
        Proibido. Retornado quando o token não tem o escopo `dv.partner`, quando o
        cabeçalho `x-partners` é inválido ou quando o `partnerId` não é autorizado para o
        token.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/error"
    NotFound:
      description: Registro não encontrado ou fora do escopo do token.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/error"
    UnprocessableEntity:
      description: Dados inválidos ou parâmetro obrigatório ausente.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/error"
    MemberRemoved:
      description: Membro removido.
      content:
        application/json:
          schema:
            type: object
            required:
              - id
            properties:
              id:
                type: string
                format: uuid
                description: UUID do membro removido.
    MagicLink:
      description: Magic link gerado.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/magic_link"
    MagicLinkForbidden:
      description: >-
        Proibido. Além dos casos gerais, retornado quando o parceiro não tem domínio de
        painel configurado ("partner must be setup a domain to user access").
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/error"
    MerchantAccepted:
      description: Operação aceita.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/merchantRef"
    MerchantOk:
      description: Assinatura atualizada.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/merchantRef"
    ResaleAccepted:
      description: Operação aceita.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/resaleRef"
    ResaleOk:
      description: Assinatura atualizada.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/resaleRef"
    ApplicationAccepted:
      description: Operação aceita.
      content:
        application/json:
          schema:
            type: object
            required:
              - applicationId
            properties:
              applicationId:
                type: string
                format: uuid
                description: UUID da aplicação.
    ApplicationUnprocessable:
      description: >-
        Não processável. Retornado quando a aplicação não é do tipo manual
        (`application_must_be_manual_type`), quando a autorização falha
        (`permission_failed`) ou quando `permission` está ausente.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/error"

  schemas:
    error:
      type: object
      properties:
        status:
          type: string
          description: Código HTTP, como texto.
          example: "422"
        title:
          description: >-
            Mensagem de erro. Em erros de validação, é um objeto com a lista de mensagens
            de cada campo.
          oneOf:
            - type: string
            - type: object
              additionalProperties:
                type: array
                items:
                  type: string

    merchantRef:
      type: object
      required:
        - merchantId
      properties:
        merchantId:
          type: string
          format: uuid
          description: UUID da loja.

    resaleRef:
      type: object
      required:
        - resaleId
      properties:
        resaleId:
          type: string
          format: uuid
          description: UUID da revenda.

    memberRoleInput:
      type: string
      description: >-
        Papel do membro, enviado em minúsculas. As respostas o retornam em maiúsculas.
      enum:
        - owner
        - manager
        - operator

    merchantFeatureType:
      type: string
      enum:
        - DELIVERYBOT_NOTIFICATION
        - DELIVERYBOT_ASSISTANT
        - INDOOR_VIEWER
        - INDOOR_QRCODE
        - INDOOR_TABLET
        - DOMAIN_CUSTOM
        - GROWTH_DISCOUNT
        - INTEGRATION_MARKETING
        - INTEGRATION_LOGISTIC

    itemType:
      type: string
      description: Recurso cobrado.
      enum:
        - DELIVERY_TAKEOUT
        - DELIVERYBOT_NOTIFICATION
        - DELIVERYBOT_ASSISTANT
        - INDOOR_VIEWER
        - INDOOR_QRCODE
        - INDOOR_TABLET
        - DOMAIN_CUSTOM
        - GROWTH_DISCOUNT
        - INTEGRATION_MARKETING
        - INTEGRATION_LOGISTIC
        - SALES_REVENUE
        - ORDERS_COUNT
        - MULTI_STORE

    totalPrice:
      type: object
      required:
        - type
        - value
        - usageTimeValue
        - currency
      properties:
        type:
          type: string
          description: >-
            `PAYABLE` é o valor devido à DeliveryVip (ou ao parceiro, no caso de revendas);
            `RECEIVABLE` é o valor a receber da loja pela tabela de preços própria.
          enum:
            - PAYABLE
            - RECEIVABLE
        value:
          type: number
          format: float
          description: Valor cheio do mês.
        usageTimeValue:
          type: number
          format: float
          description: Valor proporcional aos dias em que a loja ficou ativa no mês.
        currency:
          type: string
          description: Moeda.
          example: BRL

    addressInput:
      type: object
      required:
        - postalCode
        - street
        - number
        - district
        - city
        - state
      properties:
        postalCode:
          type: string
          description: CEP.
        street:
          type: string
          description: Logradouro.
        number:
          type: string
          description: Número.
        district:
          type: string
          description: Bairro.
        city:
          type: string
          description: Cidade.
        state:
          type: string
          description: UF.

    address:
      type: object
      required:
        - country
        - state
        - city
        - district
        - street
        - number
        - postalCode
        - formattedAddress
        - coordinates
      properties:
        country:
          type: string
          description: País.
        state:
          type: string
          description: UF.
        city:
          type: string
          description: Cidade.
        district:
          type: string
          description: Bairro.
        street:
          type: string
          description: Logradouro.
        number:
          type: string
          description: Número.
        complement:
          type: string
          description: Complemento. Omitido quando vazio.
        reference:
          type: string
          description: Ponto de referência. Omitido quando vazio.
        postalCode:
          type: string
          description: CEP.
        formattedAddress:
          type: string
          description: Endereço completo formatado.
        coordinates:
          type: object
          properties:
            latitude:
              type: number
              format: float
              nullable: true
            longitude:
              type: number
              format: float
              nullable: true

    phone:
      type: object
      required:
        - number
      properties:
        number:
          type: string
          description: Telefone no formato E.164 sem o sinal de mais.
          example: "5511987654321"

    plan:
      type: object
      required:
        - id
        - name
        - standard
        - code
        - status
        - visibility
        - features
      properties:
        id:
          type: string
          format: uuid
          description: UUID do plano.
        name:
          type: string
          description: Nome do plano.
        standard:
          type: boolean
          description: Indica se é o plano padrão do parceiro.
        code:
          type: string
          description: Código do plano.
        status:
          type: string
          description: Status do plano.
          enum:
            - DRAFT
            - AVAILABLE
            - UNAVAILABLE
        visibility:
          type: string
          description: Para quem o plano pode ser oferecido.
          enum:
            - PUBLIC
            - PRIVATE
            - RESALE
            - DIRECT_MERCHANT
        features:
          type: array
          description: Recursos do plano.
          items:
            type: object
            required:
              - featureType
              - inclusionType
            properties:
              featureType:
                $ref: "#/components/schemas/itemType"
              inclusionType:
                type: string
                description: >-
                  `INCLUDED` quando o recurso está incluído no plano; `ADDITIONAL` quando é
                  contratado à parte.
                enum:
                  - INCLUDED
                  - ADDITIONAL

    MerchantInvoiceObject:
      type: object
      required:
        - merchantId
        - planId
        - month
        - year
        - items
      properties:
        merchantId:
          type: string
          format: uuid
          description: UUID da loja.
        planId:
          type: string
          format: uuid
          description: UUID do plano faturado.
        month:
          type: integer
          description: Mês de referência.
        year:
          type: integer
          description: Ano de referência.
        totalPrice:
          type: array
          description: >-
            Totais da fatura. Para revendas, só vem quando a revenda tem tabela de preços
            própria.
          items:
            $ref: "#/components/schemas/totalPrice"
        items:
          type: array
          description: Itens da fatura, agrupados por recurso.
          items:
            $ref: "#/components/schemas/invoiceItem"

    invoiceItem:
      type: object
      required:
        - itemType
        - quantity
      properties:
        itemType:
          $ref: "#/components/schemas/itemType"
        quantity:
          type: integer
          description: Quantidade cobrada.
        totalPrice:
          type: array
          description: Preços do item. Omitido quando não há preço visível para o token.
          items:
            $ref: "#/components/schemas/totalPrice"

    ResaleInvoiceObject:
      type: object
      required:
        - resaleId
        - month
        - year
        - totalPrice
        - plans
        - items
      properties:
        resaleId:
          type: string
          format: uuid
          description: UUID da revenda.
        month:
          type: integer
          description: Mês de referência.
        year:
          type: integer
          description: Ano de referência.
        totalPrice:
          type: array
          description: Totais da revenda no mês.
          items:
            $ref: "#/components/schemas/totalPrice"
        plans:
          type: array
          description: Totais por plano.
          items:
            type: object
            required:
              - id
              - name
              - code
              - totalSubscriptions
              - totalPrice
            properties:
              id:
                type: string
                format: uuid
                description: UUID do plano.
              name:
                type: string
                description: Nome do plano.
              code:
                type: string
                description: Código do plano.
              totalSubscriptions:
                type: integer
                description: Quantidade de assinaturas no plano.
              totalPrice:
                type: array
                items:
                  $ref: "#/components/schemas/totalPrice"
        items:
          type: array
          description: Totais por recurso.
          items:
            type: object
            required:
              - itemType
              - quantity
              - totalPrice
            properties:
              itemType:
                $ref: "#/components/schemas/itemType"
              quantity:
                type: integer
                description: Quantidade cobrada.
              totalPrice:
                type: array
                items:
                  $ref: "#/components/schemas/totalPrice"

    invoice:
      type: object
      required:
        - merchantId
        - planId
        - month
        - year
        - items
      properties:
        merchantId:
          type: string
          format: uuid
          description: UUID da loja.
        resaleId:
          type: string
          format: uuid
          description: >-
            UUID da revenda que vendeu a loja. Só vem para parceiros e quando a loja é de
            uma revenda.
        planId:
          type: string
          format: uuid
          description: UUID do plano faturado.
        month:
          type: integer
          description: Mês de referência.
        year:
          type: integer
          description: Ano de referência.
        totalPrice:
          type: array
          description: >-
            Totais da fatura. Para revendas, só vem quando a revenda tem tabela de preços
            própria.
          items:
            $ref: "#/components/schemas/totalPrice"
        items:
          type: array
          description: Itens da fatura, agrupados por recurso.
          items:
            $ref: "#/components/schemas/invoiceItem"

    legacyInvoiceItem:
      type: object
      required:
        - itemType
        - quantity
        - usageTime
      properties:
        itemType:
          $ref: "#/components/schemas/itemType"
        quantity:
          type: integer
          description: Quantidade cobrada.
        usageTime:
          type: number
          format: float
          description: Fração do mês em que o item esteve ativo.
        totalPrice:
          type: number
          format: float
          description: >-
            Preço cheio do item no mês. Só vem quando o token representa o parceiro da
            fatura (não para tokens de revenda).
        totalUsageTimePrice:
          type: number
          format: float
          description: >-
            Preço proporcional a `usageTime`. Só vem quando o token representa o parceiro
            da fatura (não para tokens de revenda).
        metadata:
          $ref: "#/components/schemas/InvoiceItemMetadata"

    invoiceMerchant:
      type: object
      required:
        - merchantId
        - partnerId
        - month
        - year
        - items
      properties:
        merchantId:
          type: string
          format: uuid
          description: UUID da loja.
        partnerId:
          type: string
          format: uuid
          description: UUID do parceiro da fatura.
        resaleId:
          type: string
          format: uuid
          description: UUID da revenda. Omitido quando a loja não é de revenda.
        month:
          type: integer
          description: Mês de referência.
        year:
          type: integer
          description: Ano de referência.
        items:
          type: array
          items:
            $ref: "#/components/schemas/legacyInvoiceItem"

    invoiceResale:
      type: object
      required:
        - resaleId
        - partnerId
        - month
        - year
        - items
      properties:
        resaleId:
          type: string
          format: uuid
          description: UUID da revenda.
        partnerId:
          type: string
          format: uuid
          description: UUID do parceiro da fatura.
        month:
          type: integer
          description: Mês de referência.
        year:
          type: integer
          description: Ano de referência.
        items:
          type: array
          items:
            $ref: "#/components/schemas/legacyInvoiceItem"

    InvoiceItemMetadata:
      type: object
      description: >-
        Presente só em itens `DELIVERY_TAKEOUT` que têm metadados. Omitido para tokens que
        não representam o parceiro da fatura quando `tieredPricingRanges` seria a única
        chave.
      properties:
        agreementCode:
          type: string
          description: Código de contrato da assinatura.
        sales:
          type: object
          description: Resumo das vendas da loja no mês.
          properties:
            all:
              $ref: "#/components/schemas/InvoiceItemSalesSummary"
            success:
              $ref: "#/components/schemas/InvoiceItemSalesSummary"
            cancelled:
              $ref: "#/components/schemas/InvoiceItemSalesSummary"
        tieredPricingRanges:
          type: array
          description: >-
            Faixas de preço, presentes quando o modelo de cobrança é `VOLUME_BASE` ou
            `TIERED_BASE`. Só vem quando o token representa o parceiro da fatura.
          items:
            type: object
            properties:
              lastUnit:
                type: integer
                nullable: true
                description: Última unidade da faixa; `null` na faixa final.
              perUnitPrice:
                type: number
                format: float
                description: Preço por unidade.
              fixedRatePrice:
                type: number
                format: float
                description: Preço fixo da faixa.
              position:
                type: integer
                description: Posição da faixa.

    InvoiceItemSalesSummary:
      type: object
      properties:
        quantity:
          type: integer
          description: Quantidade de pedidos.
        totalPrice:
          type: number
          format: float
          description: Valor total dos pedidos.

    sale:
      type: object
      required:
        - merchantId
        - ordersCount
        - ordersTotal
      properties:
        merchantId:
          type: string
          format: uuid
          description: UUID da loja.
        ordersCount:
          type: integer
          description: Quantidade de pedidos no mês.
        ordersTotal:
          type: number
          format: float
          description: Valor total dos pedidos no mês.

    subscription:
      type: object
      required:
        - status
      properties:
        status:
          type: string
          description: Status da assinatura.
          enum:
            - TRIAL
            - DEMO
            - TRIAL_EXPIRED
            - ACTIVATED
            - CANCELLED
        agreementCode:
          type: string
          description: Código de contrato. Omitido quando vazio.
        warning:
          type: boolean
          description: Indica se há aviso de bloqueio. Só vem com a assinatura ativa.
        blocked:
          type: boolean
          description: Indica se a assinatura está bloqueada. Só vem com a assinatura ativa.
        trialExpiresAt:
          type: string
          format: date-time
          description: Fim do período de teste. Só vem durante o teste (`TRIAL`).
        lastActivationAt:
          type: string
          format: date-time
          description: Data da última ativação.
        lastCancellationAt:
          type: string
          format: date-time
          description: Data do último cancelamento.
        lastBlockedAt:
          type: string
          format: date-time
          description: Data do último bloqueio. Só vem com a assinatura ativa.
        lastWarningAt:
          type: string
          format: date-time
          description: Data do último aviso. Só vem com a assinatura ativa.

    merchant:
      type: object
      required:
        - id
        - name
        - createdAt
        - updatedAt
        - address
        - subscription
        - features
        - partnerId
      properties:
        id:
          type: string
          format: uuid
          description: UUID da loja.
        name:
          type: string
          description: Nome fantasia.
        corporateName:
          type: string
          description: Razão social. Omitida quando vazia.
        identifier:
          type: string
          description: CNPJ ou CPF. Omitido quando vazio.
        email:
          type: string
          description: E-mail da loja. Omitido quando vazio.
        phone:
          $ref: "#/components/schemas/phone"
        storeUrl:
          type: string
          description: URL do domínio principal da loja. Omitida quando não há domínio.
        createdAt:
          type: string
          format: date-time
          description: Data de criação.
        updatedAt:
          type: string
          format: date-time
          description: Data da última alteração.
        personResponsible:
          type: object
          description: Responsável pela loja. Omitido quando não há nenhum dado.
          properties:
            name:
              type: string
              description: Nome do responsável.
            email:
              type: string
              description: E-mail do responsável.
            phone:
              $ref: "#/components/schemas/phone"
            identifier:
              type: string
              description: CPF do responsável.
        address:
          $ref: "#/components/schemas/address"
        subscription:
          allOf:
            - $ref: "#/components/schemas/subscription"
            - type: object
              properties:
                planId:
                  type: string
                  format: uuid
                  description: UUID do plano da assinatura. Omitido quando não há plano.
        features:
          type: array
          description: Recursos adicionais da loja.
          items:
            type: object
            required:
              - featureType
              - status
            properties:
              featureType:
                $ref: "#/components/schemas/merchantFeatureType"
              status:
                type: string
                description: >-
                  `ACTIVATED` quando contratado; `CANCELLED` quando cancelado e ainda dentro
                  da janela em que não pode ser recontratado; `AVAILABLE` nos demais casos.
                enum:
                  - ACTIVATED
                  - AVAILABLE
                  - CANCELLED
              lastActivationAt:
                type: string
                format: date-time
                description: Data da última contratação.
              lastCancellationAt:
                type: string
                format: date-time
                description: Data do último cancelamento. Só vem quando não está contratado.
        partnerId:
          type: string
          format: uuid
          description: UUID do parceiro.
        resaleId:
          type: string
          format: uuid
          description: UUID da revenda. Omitido quando a loja não é de revenda.

    resale:
      type: object
      required:
        - id
        - name
        - createdAt
        - updatedAt
        - personResponsible
        - address
        - subscription
        - partnerId
      properties:
        id:
          type: string
          format: uuid
          description: UUID da revenda.
        name:
          type: string
          description: Nome fantasia.
        corporateName:
          type: string
          description: Razão social. Omitida quando vazia.
        identifier:
          type: string
          description: CNPJ ou CPF. Omitido quando vazio.
        email:
          type: string
          description: E-mail da revenda. Omitido quando vazio.
        phone:
          $ref: "#/components/schemas/phone"
        createdAt:
          type: string
          format: date-time
          description: Data de criação.
        updatedAt:
          type: string
          format: date-time
          description: Data da última alteração.
        personResponsible:
          type: object
          description: Responsável pela revenda. Campos vazios são omitidos.
          properties:
            name:
              type: string
              description: Nome do responsável.
            email:
              type: string
              description: E-mail do responsável.
            phone:
              $ref: "#/components/schemas/phone"
            document:
              type: string
              description: CPF do responsável.
        address:
          $ref: "#/components/schemas/address"
        subscription:
          $ref: "#/components/schemas/subscription"
        partnerId:
          type: string
          format: uuid
          description: UUID do parceiro.

    member:
      type: object
      required:
        - id
        - role
        - user
        - status
      properties:
        id:
          type: string
          format: uuid
          description: UUID do membro.
        role:
          type: string
          description: >-
            Papel do membro, retornado em maiúsculas. As requisições devem enviá-lo em
            minúsculas.
          enum:
            - OWNER
            - MANAGER
            - OPERATOR
        status:
          type: string
          description: >-
            `ACTIVE` quando o vínculo está ligado a uma conta de usuário. `INVITED` quando o
            e-mail já pertencia a uma conta existente: o vínculo só é efetivado depois que o
            dono aceitar o convite enviado para esse endereço.
          enum:
            - ACTIVE
            - INVITED
        user:
          type: object
          required:
            - name
            - email
          properties:
            name:
              type: string
              description: >-
                Nome do usuário. Para um membro `INVITED` a conta ainda não está vinculada,
                então este campo traz o e-mail do convite no lugar do nome.
            email:
              type: string
              format: email
              description: E-mail do usuário.

    magic_link:
      type: object
      required:
        - magicLink
        - magicLinkExpiresAt
      properties:
        magicLink:
          type: string
          format: uri
          description: Link de entrada no painel, de uso único.
        magicLinkExpiresAt:
          type: string
          format: date-time
          description: Data de expiração do link (6 horas após a geração).

  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Access token OAuth 2.0 (opaco) com o escopo `dv.partner`, obtido em
        `POST /authentication/v1/oauth/token`.
