# openapi-web-api — contrato público ERP Nuvartis (/web_api)
openapi: 3.0.3
info:
  title: Nuvartis ERP API
  version: '1'
  description: |
    Contrato HTTP para ERPs sob `/web_api`.

    **Portal:** https://nuvartis.com/developers  
    **Base:** `https://api.nuvartis.com/web_api`

    ### Autenticação
    1. O lojista autoriza seu app no painel e você recebe um `code`.
    2. `POST /auth` com `consumer_key`, `consumer_secret` e `code` → `access_token` + `refresh_token`.
    3. Envie o `access_token` em query (`?access_token=`) ou no header `Authorization: Bearer`.
    4. Antes de expirar, `POST /auth` com `refresh_token`.

    A loja é definida pelo token. Não envie `store_id` (query/body) nem header `X-Store-Id`: a requisição responde **404**.

    ### Escopos
    O app recebe escopos no cadastro. Escopo `:write` inclui o `:read` do mesmo recurso.

    | Escopo | Recursos |
    |--------|----------|
    | `catalog:read` / `catalog:write` | produtos, variações, imagens, categorias, marcas, propriedades, kits, listas de preço |
    | `orders:read` / `orders:write` | pedidos, status de pedido |
    | `customers:read` / `customers:write` | clientes, endereços, perfis |
    | `shipping:read` / `shipping:write` | formas de envio, cotação |
    | `warehouses:read` / `warehouses:write` | centros de distribuição e estoque por CD |
    | `coupons:read` / `coupons:write` | cupons de desconto |
    | `invoices:read` / `invoices:write` | notas fiscais |
    | `payments:read` / `payments:write` | pagamentos |
    | `carts:read` / `carts:write` | carrinhos |
    | `webhooks:read` / `webhooks:write` | webhook do app |
    | `store:read` | dados da loja |

    ### Erros
    Corpo: `{ "code": <int>, "message": "<texto>" }`.

    | Code | HTTP | Significado |
    |------|------|-------------|
    | 1000 | 401 | `consumer_key` / `consumer_secret` inválidos |
    | 1001 | 401 | `code` inválido, expirado ou já usado |
    | 1002 | 401 | `refresh_token` inválido ou expirado |
    | 1003 | 401 | App desativado |
    | 1004 | 429 | Limite de requisições por minuto |
    | 1005 | 403 | Plano da loja não inclui a API, ou loja não liberada para o app |
    | 1006 | 401 | `access_token` ausente, inválido ou expirado (inclui autorização revogada pelo lojista) |
    | 1008 | 409 | `Idempotency-Key` reutilizada com corpo diferente |
    | 1009 | 403 | Escopo insuficiente |
    | 1100 | 404 | Recurso não encontrado |
    | 1101 | 422 | Dados inválidos |
    | 9999 | 404 | Recurso não disponível nesta API (`nuvartis_stub: true`) |

    ### Convenções
    - Limite por minuto: headers `X-RateLimit-Limit` e `X-RateLimit-Remaining`
    - Escritas (`POST` / `PUT` / `DELETE`): envie `Idempotency-Key` único; repetir a mesma chave com o mesmo corpo devolve a resposta original
    - Valores monetários em string decimal (ex.: `"15.00"`)

    Guia curl e homologação: https://nuvartis.com/developers  
    API merchant (outra superfície): https://nuvartis.com/documentacao
  contact:
    name: Nuvartis Developers
    url: https://nuvartis.com/developers
externalDocs:
  description: Portal developers · guia homolog
  url: https://nuvartis.com/developers
servers:
  - url: '{api_origin}/web_api'
    variables:
      api_origin:
        default: https://api.nuvartis.com
paths:
  /auth:
    post:
      summary: Exchange code or refresh token (body preferred)
      operationId: webApiAuthExchange
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [consumer_key, consumer_secret]
              properties:
                consumer_key: { type: string }
                consumer_secret: { type: string }
                code: { type: string, description: Exchange authorization code }
                refresh_token: { type: string, description: Preferred refresh (avoids secret in query) }
      responses:
        '200':
          description: Tokens
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthTokens'
        '401':
          $ref: '#/components/responses/ApiError'
    get:
      summary: Refresh access token (prefer POST body)
      operationId: webApiAuthRefresh
      parameters:
        - name: consumer_key
          in: query
          required: true
          schema: { type: string }
        - name: consumer_secret
          in: query
          required: true
          schema: { type: string }
        - name: refresh_token
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Tokens
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthTokens'
        '401':
          $ref: '#/components/responses/ApiError'
  /ping:
    get:
      summary: Validate access_token
      description: Requires an active installation on a plan with API access; counts toward the per-minute quota.
      operationId: webApiPing
      parameters:
        - name: access_token
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: OK (no internal ids)
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  api_address: { type: string }
        '401':
          $ref: '#/components/responses/ApiError'
        '403':
          $ref: '#/components/responses/ApiError'
  /products:
    get:
      summary: List products
      operationId: webApiProductsIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: page
          in: query
          schema: { type: integer, minimum: 1, default: 1 }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 50, default: 50 }
      responses:
        '200':
          description: Products + paging
        '401':
          $ref: '#/components/responses/ApiError'
    post:
      summary: Create product
      description: "`name` and `price` are required. The product URL slug is generated from the name (suffix -2, -3… when taken)."
      operationId: webApiProductsStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                Product: { $ref: '#/components/schemas/Product' }
      responses:
        '201':
          description: Created Product
        '401':
          $ref: '#/components/responses/ApiError'
        '422':
          $ref: '#/components/responses/ApiError'
  /products/{product}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: product
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: Get product
      operationId: webApiProductsShow
      responses:
        '200':
          description: Product
          content:
            application/json:
              schema:
                type: object
                properties:
                  Product: { $ref: '#/components/schemas/Product' }
        '404':
          $ref: '#/components/responses/ApiError'
    put:
      summary: Update product
      operationId: webApiProductsUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                Product: { $ref: '#/components/schemas/Product' }
      responses:
        '200':
          description: Updated Product
    delete:
      summary: Archive/delete product
      operationId: webApiProductsDestroy
      responses:
        '200':
          description: OK
  /products/{product}/variants:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: product
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: List variants
      operationId: webApiVariantsIndex
      responses:
        '200':
          description: Variants
    post:
      summary: Create variant
      operationId: webApiVariantsStore
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Variant
  /products/{product}/images:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: product
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: List images
      operationId: webApiImagesIndex
      responses:
        '200':
          description: Images
    post:
      summary: Attach image from HTTPS URL
      operationId: webApiImagesStore
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                Image:
                  type: object
                  properties:
                    http: { type: string, format: uri }
      responses:
        '201':
          description: Image
  /products/{product}/variants/{variant}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: product
        in: path
        required: true
        schema: { type: integer }
      - name: variant
        in: path
        required: true
        schema: { type: integer }
    put:
      summary: Update variant
      operationId: webApiVariantsUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Variant
        '404':
          $ref: '#/components/responses/ApiError'
    delete:
      summary: Delete variant
      operationId: webApiVariantsDestroy
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: OK
        '404':
          $ref: '#/components/responses/ApiError'
  /products/{product}/images/{image}:
    delete:
      summary: Delete image
      operationId: webApiImagesDestroy
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: product
          in: path
          required: true
          schema: { type: integer }
        - name: image
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: OK
        '404':
          $ref: '#/components/responses/ApiError'
  /categories:
    get:
      summary: Category tree
      operationId: webApiCategoriesTree
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Nested Category tree
    post:
      summary: Create category
      operationId: webApiCategoriesStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                Category: { $ref: '#/components/schemas/Category' }
      responses:
        '201':
          description: Created Category
  /categories/all:
    get:
      summary: Flat categories list
      operationId: webApiCategoriesAll
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Categories
  /categories/{category}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: category
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: Get category
      operationId: webApiCategoriesShow
      responses:
        '200':
          description: Category
          content:
            application/json:
              schema:
                type: object
                properties:
                  Category: { $ref: '#/components/schemas/Category' }
    put:
      summary: Update category
      operationId: webApiCategoriesUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Updated Category
    delete:
      summary: Delete category
      operationId: webApiCategoriesDestroy
      responses:
        '200':
          description: OK
  /categories/{category}/order:
    put:
      summary: Update category order
      operationId: webApiCategoriesOrder
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: category
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Category
  /products/brands:
    get:
      summary: List brands
      operationId: webApiBrandsIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: page
          in: query
          schema: { type: integer, minimum: 1, default: 1 }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 50, default: 50 }
      responses:
        '200':
          description: Brands + paging
    post:
      summary: Create brand
      operationId: webApiBrandsStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                Brand: { $ref: '#/components/schemas/Brand' }
      responses:
        '201':
          description: Created Brand
  /products/brands/{brand}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: brand
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: Get brand
      operationId: webApiBrandsShow
      responses:
        '200':
          description: Brand
          content:
            application/json:
              schema:
                type: object
                properties:
                  Brand: { $ref: '#/components/schemas/Brand' }
    put:
      summary: Update brand
      operationId: webApiBrandsUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Updated Brand
    delete:
      summary: Delete brand
      operationId: webApiBrandsDestroy
      responses:
        '200':
          description: OK
  /products/properties:
    get:
      summary: List global properties
      operationId: webApiPropertiesGlobalIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Properties
  /properties:
    post:
      summary: Create global property
      operationId: webApiPropertiesGlobalStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Property
  /properties/{property}:
    delete:
      summary: Delete global property
      operationId: webApiPropertiesGlobalDestroy
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: property
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: OK
  /products/{product}/properties:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: product
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: List product properties
      operationId: webApiProductPropertiesIndex
      responses:
        '200':
          description: Properties
    post:
      summary: Upsert product property
      operationId: webApiProductPropertiesStore
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Property
  /products/{product}/properties/{property}:
    delete:
      summary: Remove property from product
      operationId: webApiProductPropertiesDestroy
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: product
          in: path
          required: true
          schema: { type: integer }
        - name: property
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: OK
        '404':
          $ref: '#/components/responses/ApiError'
  /orders:
    get:
      summary: List orders
      operationId: webApiOrdersIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: page
          in: query
          schema: { type: integer, minimum: 1, default: 1 }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 50, default: 50 }
        - name: status_id
          in: query
          schema: { type: integer }
      responses:
        '200':
          description: Orders + paging
    post:
      summary: Create order (manual_order plan)
      operationId: webApiOrdersStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Created Order
  /orders/statuses:
    get:
      summary: List mapped order statuses
      operationId: webApiOrderStatusesIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: OrderStatuses
    post:
      summary: Create custom status (not available)
      operationId: webApiOrderStatusesStoreStub
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '404':
          description: nuvartis_stub
  /orders/statuses/{status}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: status
        in: path
        required: true
        schema: { type: integer }
    put:
      summary: Update custom status (not available)
      operationId: webApiOrderStatusesUpdateStub
      responses:
        '404':
          description: nuvartis_stub
    delete:
      summary: Delete custom status (not available)
      operationId: webApiOrderStatusesDestroyStub
      responses:
        '404':
          description: nuvartis_stub
  /orders/{order}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: order
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: Get order
      operationId: webApiOrdersShow
      responses:
        '200':
          description: Order
          content:
            application/json:
              schema:
                type: object
                properties:
                  Order: { $ref: '#/components/schemas/Order' }
    put:
      summary: Update order status / tracking
      description: "Refunds (`status_id` 6) are not accepted: they return money at the payment provider and are done only from the store admin. Cancelled or refunded orders cannot change status, and orders cannot go back to pending payment."
      operationId: webApiOrdersUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Updated Order
        '422':
          $ref: '#/components/responses/ApiError'
  /orders/{order}/full:
    get:
      summary: Get order full
      operationId: webApiOrdersFull
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: order
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Order + Customer + ProductsSold
  /orders/{order}/cancel:
    put:
      summary: Cancel order
      operationId: webApiOrdersCancel
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: order
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Cancelled Order
  /customers:
    get:
      summary: List customers
      operationId: webApiCustomersIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: page
          in: query
          schema: { type: integer, minimum: 1, default: 1 }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 50, default: 50 }
        - name: email
          in: query
          schema: { type: string }
      responses:
        '200':
          description: Customers + paging
    post:
      summary: Create customer
      operationId: webApiCustomersStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Created Customer
  /customers/{customer}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: customer
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: Get customer
      operationId: webApiCustomersShow
      responses:
        '200':
          description: Customer
          content:
            application/json:
              schema:
                type: object
                properties:
                  Customer: { $ref: '#/components/schemas/Customer' }
    put:
      summary: Update customer
      operationId: webApiCustomersUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Updated Customer
    delete:
      summary: Delete customer
      description: Anonymizes personal data and removes the customer. Order history is kept; the same e-mail can be registered again.
      operationId: webApiCustomersDestroy
      responses:
        '200':
          description: OK
  /customers/addresses:
    get:
      summary: List primary addresses
      operationId: webApiCustomerAddressesIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: customer_id
          in: query
          schema: { type: integer }
      responses:
        '200':
          description: CustomerAddresses
    post:
      summary: Upsert primary address
      operationId: webApiCustomerAddressesStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: CustomerAddress
  /customers/addresses/{address}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: address
        in: path
        required: true
        schema: { type: integer, description: 'Primary address id = customer_id' }
    get:
      summary: Get primary address
      operationId: webApiCustomerAddressesShow
      responses:
        '200':
          description: CustomerAddress
    put:
      summary: Update primary address
      operationId: webApiCustomerAddressesUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: CustomerAddress
    delete:
      summary: Clear primary address fields
      operationId: webApiCustomerAddressesDestroy
      responses:
        '200':
          description: OK
  /shippings:
    get:
      summary: List active shipping methods
      operationId: webApiShippingsIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Shippings (UF table · custom · pickup)
          content:
            application/json:
              schema:
                type: object
                properties:
                  Shippings:
                    type: array
                    items:
                      type: object
                      properties:
                        Shipping: { $ref: '#/components/schemas/Shipping' }
  /shippings/cotation:
    get:
      summary: Quote shipping
      operationId: webApiShippingsCotation
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: zipcode
          in: query
          required: true
          schema: { type: string, description: '8-digit CEP' }
        - name: products
          in: query
          required: true
          schema:
            type: array
            items:
              type: object
              properties:
                product_id: { type: integer }
                quantity: { type: integer, minimum: 1 }
                price: { type: number }
      responses:
        '200':
          description: Shippings quote options
          content:
            application/json:
              schema:
                type: object
                properties:
                  Shippings:
                    type: array
                    items:
                      type: object
                      properties:
                        Shipping: { $ref: '#/components/schemas/Shipping' }
        '404':
          $ref: '#/components/responses/ApiError'
        '422':
          $ref: '#/components/responses/ApiError'
  /shippings/method/gateway:
    post:
      summary: Configure gateway method (stub)
      operationId: webApiShippingsMethodGatewayStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '404':
          description: nuvartis_stub
  /shippings/method/gateway/{id}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: id
        in: path
        required: true
        schema: { type: integer }
    put:
      summary: Update gateway method (stub)
      operationId: webApiShippingsMethodGatewayUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '404':
          description: nuvartis_stub
    delete:
      summary: Delete gateway method (stub)
      operationId: webApiShippingsMethodGatewayDestroy
      responses:
        '404':
          description: nuvartis_stub
  /shippings/method/zipcode_table:
    post:
      summary: Configure zipcode table method (stub)
      operationId: webApiShippingsMethodZipcodeStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '404':
          description: nuvartis_stub
  /shippings/method/zipcode_table/{id}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: id
        in: path
        required: true
        schema: { type: integer }
    put:
      summary: Update zipcode table method (stub)
      operationId: webApiShippingsMethodZipcodeUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '404':
          description: nuvartis_stub
    delete:
      summary: Delete zipcode table method (stub)
      operationId: webApiShippingsMethodZipcodeDestroy
      responses:
        '404':
          description: nuvartis_stub
  /multicd/distribution-centers:
    get:
      summary: List distribution centers
      operationId: webApiMulticdCentersIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: page
          in: query
          schema: { type: integer, minimum: 1, default: 1 }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 50, default: 30 }
      responses:
        '200':
          description: data + paging (MultiCD)
    post:
      summary: Create distribution center
      operationId: webApiMulticdCentersStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Distribution center
  /multicd/distribution-centers/{id}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: id
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: Get distribution center
      operationId: webApiMulticdCentersShow
      responses:
        '200':
          description: Distribution center
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DistributionCenter'
    put:
      summary: Update distribution center
      operationId: webApiMulticdCentersUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Distribution center
    delete:
      summary: Delete distribution center
      operationId: webApiMulticdCentersDestroy
      responses:
        '200':
          description: OK
  /multicd/distribution-centers/{id}/stock:
    put:
      summary: Set stock for product/variant in CD
      operationId: webApiMulticdCentersSetStock
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: stock detailed shape
  /multicd/stock/detailed/product/{id}:
    get:
      summary: Stock per CD for product (sum variants)
      operationId: webApiMulticdStockDetailedProduct
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: message + data[{dc_id,stock}]
  /multicd/stock/detailed/variant/{id}:
    get:
      summary: Stock per CD for variant
      operationId: webApiMulticdStockDetailedVariant
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: message + data[{dc_id,stock}]
  /discount_coupons:
    get:
      summary: List discount coupons
      operationId: webApiDiscountCouponsIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: page
          in: query
          schema: { type: integer, minimum: 1, default: 1 }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 50, default: 30 }
      responses:
        '200':
          description: DiscountCoupons + paging
    post:
      summary: Create discount coupon
      operationId: webApiDiscountCouponsStore
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: DiscountCoupon
  /discount_coupons/{id}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: id
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: Get discount coupon
      operationId: webApiDiscountCouponsShow
      responses:
        '200':
          description: DiscountCoupon
          content:
            application/json:
              schema:
                type: object
                properties:
                  DiscountCoupon: { $ref: '#/components/schemas/DiscountCoupon' }
    put:
      summary: Update discount coupon
      operationId: webApiDiscountCouponsUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: DiscountCoupon
    delete:
      summary: Delete discount coupon
      operationId: webApiDiscountCouponsDestroy
      responses:
        '200':
          description: OK
  /discount_coupons/product_relationship/{id}:
    get:
      summary: Product links (always empty list)
      operationId: webApiDiscountCouponsProductRel
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: DiscountCouponProducts []
  /discount_coupons/customer_relationship/{id}:
    get:
      summary: Customer links (always empty list)
      operationId: webApiDiscountCouponsCustomerRel
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: DiscountCouponCustomers []
  /discount_coupons/category_relationship/{id}:
    get:
      summary: Category links (always empty list)
      operationId: webApiDiscountCouponsCategoryRel
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: DiscountCouponCategories []
  /discount_coupons/brand_relationship/{id}:
    get:
      summary: Brand links (always empty list)
      operationId: webApiDiscountCouponsBrandRel
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: DiscountCouponBrands []
  /discount_coupons/shipping_relationship/{id}:
    get:
      summary: Shipping links (always empty list)
      operationId: webApiDiscountCouponsShippingRel
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: DiscountCouponShippings []
  /discount_coupons/create_relationship/{id}:
    post:
      summary: Create coupon relationship (stub; 404 coupon missing)
      operationId: webApiDiscountCouponsCreateRel
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '404':
          description: nuvartis_stub (coupon exists) or code 1100 (missing)
  /store:
    get:
      summary: Store info
      operationId: webApiStoreShow
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Store wrapper
          content:
            application/json:
              schema:
                type: object
                properties:
                  Store: { $ref: '#/components/schemas/Store' }
  /info:
    get:
      summary: Store info (alias)
      operationId: webApiInfoShow
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Store wrapper
          content:
            application/json:
              schema:
                type: object
                properties:
                  Store: { $ref: '#/components/schemas/Store' }
  /webhooks:
    get:
      summary: Get partner webhook notification URL
      operationId: webApiWebhooksShow
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Webhook config
          content:
            application/json:
              schema:
                type: object
                properties:
                  Webhook: { $ref: '#/components/schemas/Webhook' }
    put:
      summary: Upsert partner webhook URL + events
      operationId: webApiWebhooksUpdate
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Webhook config
    delete:
      summary: Deactivate partner webhook
      operationId: webApiWebhooksDestroy
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Webhook config
  /orders/invoices:
    get:
      summary: List invoices
      operationId: webApiOrdersInvoicesIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/Limit30'
        - $ref: '#/components/parameters/InvoiceOrderFilter'
      responses:
        '200':
          description: Invoices + paging
  /invoices:
    get:
      summary: List invoices (alias of /orders/invoices)
      operationId: webApiInvoicesIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/Limit30'
        - $ref: '#/components/parameters/InvoiceOrderFilter'
      responses:
        '200':
          description: Invoices + paging
  /orders/{order}/invoices:
    get:
      summary: Invoices for order
      operationId: webApiOrderInvoices
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: order
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Invoices wrapper
    post:
      summary: Create or replace the order invoice
      operationId: webApiOrderInvoicesCreate
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: order
          in: path
          required: true
          schema: { type: integer }
      responses:
        '201':
          description: Created
  /orders/{order}/invoices/{invoice}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: order
        in: path
        required: true
        schema: { type: integer }
      - name: invoice
        in: path
        required: true
        schema: { type: integer, description: 'Equals the order id (one invoice per order)' }
    get:
      summary: Show order invoice
      operationId: webApiOrderInvoiceShow
      responses:
        '200':
          description: Invoice wrapper
        '404':
          $ref: '#/components/responses/ApiError'
    put:
      summary: Update order invoice
      operationId: webApiOrderInvoiceUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Saved
        '404':
          $ref: '#/components/responses/ApiError'
  /invoices/{invoice}:
    get:
      summary: Show invoice (id = order id)
      operationId: webApiInvoiceShow
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: invoice
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Invoice wrapper
          content:
            application/json:
              schema:
                type: object
                properties:
                  Invoice: { $ref: '#/components/schemas/Invoice' }
    put:
      summary: Update invoice
      operationId: webApiInvoiceUpdate
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: invoice
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Saved
  /payments:
    get:
      summary: List payments (one per order)
      operationId: webApiPaymentsIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: Payments list
    post:
      summary: Register payment on order
      operationId: webApiPaymentsCreate
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Created
  /payments/options:
    get:
      summary: Payment options enabled for the store
      operationId: webApiPaymentsOptions
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: PaymentOptions
  /payments/settings:
    get:
      summary: Payment settings
      operationId: webApiPaymentsSettings
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '200':
          description: PaymentSettings
  /payments/{payment}:
    get:
      summary: Show payment (id = order id)
      operationId: webApiPaymentsShow
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: payment
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Payment wrapper
          content:
            application/json:
              schema:
                type: object
                properties:
                  Payment: { $ref: '#/components/schemas/Payment' }
    put:
      summary: Update payment
      operationId: webApiPaymentsUpdate
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: payment
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Saved
    delete:
      summary: Clear payment data
      operationId: webApiPaymentsDelete
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: payment
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Cleared
  /products/kits:
    get:
      summary: List kits
      operationId: webApiKitsIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/Limit50'
      responses:
        '200':
          description: Kits + paging
    post:
      summary: Create kit
      operationId: webApiKitsCreate
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Kit created
  /products/kits/{kit}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: kit
        in: path
        required: true
        schema: { type: integer }
    get:
      summary: Get kit
      operationId: webApiKitsShow
      responses:
        '200':
          description: Kit
        '404':
          $ref: '#/components/responses/ApiError'
    put:
      summary: Update kit
      operationId: webApiKitsUpdate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Kit
    delete:
      summary: Delete kit
      operationId: webApiKitsDestroyProductsPath
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Deleted
  /kits/{kit}:
    delete:
      summary: Delete kit (alias of DELETE /products/kits/{kit})
      operationId: webApiKitsDestroy
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: kit
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Deleted
  /carts:
    get:
      summary: List carts
      operationId: webApiCartsIndex
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/Limit30'
      responses:
        '200':
          description: Carts + paging
    post:
      summary: Create cart (not available)
      operationId: webApiCartsCreateStub
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '404':
          description: nuvartis_stub
    put:
      summary: Update cart (not available)
      operationId: webApiCartsUpdateStub
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '404':
          description: nuvartis_stub
  /carts/{session}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: session
        in: path
        required: true
        schema: { type: string }
    get:
      summary: Get cart by session
      operationId: webApiCartsShow
      responses:
        '200':
          description: Cart lines
        '404':
          $ref: '#/components/responses/ApiError'
    delete:
      summary: Delete cart (not available)
      operationId: webApiCartsDestroyStub
      responses:
        '404':
          description: nuvartis_stub
  /carts/{session}/complete:
    get:
      summary: Cart with totals and customer
      operationId: webApiCartsComplete
      parameters:
        - $ref: '#/components/parameters/AccessToken'
        - name: session
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: CartComplete
  /products_sold:
    get:
      summary: Products sold (not available)
      operationId: webApiProductsSoldStub
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '404':
          description: nuvartis_stub
  /price_lists:
    get:
      summary: B2B price lists (not available)
      operationId: webApiPriceListsStub
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '404':
          description: nuvartis_stub
    post:
      summary: Create price list (not available)
      operationId: webApiPriceListsStoreStub
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '404':
          description: nuvartis_stub
  /price_lists/{id}:
    parameters:
      - $ref: '#/components/parameters/AccessToken'
      - name: id
        in: path
        required: true
        schema: { type: integer }
    put:
      summary: Update price list (not available)
      operationId: webApiPriceListsUpdateStub
      responses:
        '404':
          description: nuvartis_stub
    delete:
      summary: Delete price list (not available)
      operationId: webApiPriceListsDestroyStub
      responses:
        '404':
          description: nuvartis_stub
  /customers/profiles:
    get:
      summary: Customer profiles (not available)
      operationId: webApiCustomerProfilesStub
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '404':
          description: nuvartis_stub
    post:
      summary: Create customer profile (not available)
      operationId: webApiCustomerProfilesStoreStub
      parameters:
        - $ref: '#/components/parameters/AccessToken'
      responses:
        '404':
          description: nuvartis_stub

components:
  parameters:
    AccessToken:
      name: access_token
      in: query
      required: true
      schema: { type: string }
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: Unique per write; same key + same body replays the original response
      schema: { type: string }
    Page:
      name: page
      in: query
      schema: { type: integer, minimum: 1, default: 1 }
    Limit30:
      name: limit
      in: query
      schema: { type: integer, minimum: 1, maximum: 50, default: 30 }
    Limit50:
      name: limit
      in: query
      schema: { type: integer, minimum: 1, maximum: 50, default: 50 }
    InvoiceOrderFilter:
      name: order_id
      in: query
      description: Filter by order
      schema: { type: integer }
  schemas:
    AuthTokens:
      type: object
      properties:
        access_token: { type: string }
        refresh_token: { type: string }
        date_expiration_access_token: { type: string, format: date-time }
        date_expiration_refresh_token: { type: string, format: date-time }
        api_address: { type: string }
    Product:
      type: object
      properties:
        id: { type: string }
        name: { type: string }
        description: { type: string }
        price: { type: string }
        cost_price: { type: string, nullable: true }
        stock: { type: string }
        ean: { type: string, nullable: true }
        reference: { type: string, nullable: true }
        brand: { type: string, nullable: true }
        brand_id: { type: string, nullable: true }
        category_id: { type: string, nullable: true }
        available: { type: string }
        slug: { type: string }
    Category:
      type: object
      properties:
        id: { type: string }
        name: { type: string }
        description: { type: string }
        parent_id: { type: string }
        slug: { type: string }
        order: { type: string }
        has_product: { type: string }
    Brand:
      type: object
      properties:
        id: { type: string }
        brand: { type: string, description: 'Wire field is brand (not name)' }
        slug: { type: string }
        image: { type: string, nullable: true }
    Order:
      type: object
      properties:
        id: { type: string }
        status_id: { type: string, nullable: true }
        status: { type: string }
        partial_total: { type: string }
        taxes: { type: string }
        discount: { type: string }
        shipping: { type: string }
        total: { type: string }
        customer_id: { type: string, nullable: true }
        payment_method: { type: string, nullable: true }
        tracking_number: { type: string, nullable: true }
        date: { type: string }
        modified: { type: string }
        order_number: { type: string }
    Customer:
      type: object
      properties:
        id: { type: string }
        name: { type: string }
        email: { type: string }
        birth_date: { type: string, nullable: true }
        cpf: { type: string, nullable: true }
        cnpj: { type: string, nullable: true }
        phone: { type: string, nullable: true }
        cellphone: { type: string, nullable: true }
        newsletter: { type: string }
    Shipping:
      type: object
      properties:
        code: { type: string }
        name: { type: string }
        price: { type: string, description: 'Decimal string BRL (e.g. 15.00)' }
        delivery_time: { type: string, nullable: true }
        display_name: { type: string }
        company: { type: string, nullable: true }
        type: { type: string, nullable: true, description: 'zipcode_table · custom · pickup (list only)' }
    DistributionCenter:
      type: object
      properties:
        id: { type: integer }
        store_id: { type: integer }
        document: { type: string, nullable: true }
        name: { type: string }
        main: { type: boolean }
        status: { type: boolean }
        postal_code: { type: string }
        country: { type: string }
        state: { type: string }
        city: { type: string }
        address: { type: string }
        number: { type: string }
        neighborhood: { type: string }
        complement: { type: string }
        configs:
          type: object
          properties:
            config_zipcodes: { type: boolean }
        created_at: { type: string, format: date-time, nullable: true }
        updated_at: { type: string, format: date-time, nullable: true }
    DiscountCoupon:
      type: object
      properties:
        id: { type: string }
        code: { type: string }
        description: { type: string }
        value: { type: string }
        type: { type: string, description: '% or $' }
        starts_at: { type: string, nullable: true }
        ends_at: { type: string, nullable: true }
        coupon_type: { type: string }
        local_application: { type: string }
        freight_application: { type: string }
        usage_counter_limit: { type: string, nullable: true }
        usage_counter: { type: string }
        value_start: { type: string, nullable: true }
        active: { type: string }
    Store:
      type: object
      properties:
        id: { type: string }
        name: { type: string }
        company_name: { type: string }
        domain: { type: string }
        status: { type: string }
        plan: { type: string }
        currency: { type: string }
        language: { type: string }
        uri: { type: string }
        secure_uri: { type: string }
    Webhook:
      type: object
      properties:
        url: { type: string, nullable: true }
        events:
          type: array
          items: { type: string }
        active: { type: string }
    Invoice:
      type: object
      properties:
        id: { type: string }
        order_id: { type: string }
        number: { type: string, nullable: true }
        series: { type: string, nullable: true }
        issue_date: { type: string, nullable: true }
        key: { type: string, nullable: true }
        cfop: { type: string, nullable: true }
        link: { type: string, nullable: true }
        total_amount: { type: string }
        created_at: { type: string }
        updated_at: { type: string }
    Payment:
      type: object
      properties:
        id: { type: string }
        order_id: { type: string }
        payment_method: { type: string }
        payment_type: { type: string }
        amount: { type: string }
        status: { type: string }
        transaction_id: { type: string, nullable: true }
        created_at: { type: string, nullable: true }
        updated_at: { type: string, nullable: true }
    ApiError:
      type: object
      properties:
        code: { type: integer, description: '1000–1099 auth · 1100+ catalog' }
        message: { type: string }
  responses:
    ApiError:
      description: Error envelope
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
