> ## Documentation Index
> Fetch the complete documentation index at: https://developers.cubbo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Update a product

> Updates the editable fields of one product: name, description, price, image, barcode, SKUs,
weight and dimensions. Only the fields you send are changed; everything else is kept.
- **SKU and barcode changes are blocked once the product has stock** in the warehouse (any unit, in any status). The whole request is rejected with 422 in that case, even if it also carries other fields.
- `skus` **replaces** the product's full SKU list: existing SKUs are removed and the ones you send are added. An empty array is treated as "no change". The new SKUs must not be in use by another product of the store.
- `bar_code` must be unique in the store and must not match a SKU of another product.
- `weight` is stored in kilograms; send `weight_unit: "g"` (or `"gr"`) to send grams and have the value converted. `weight` must be greater than 0.
- `length`, `width` and `height` must be between 0.01 and 999999.99.
- Concurrent updates of the same product are serialized; a second simultaneous update receives `202 Accepted`.
- The response is the full product in the same format the Cubbo app uses (see `ProductDetailed`).




## OpenAPI

````yaml /openapi.yaml patch /products/{id}
openapi: 3.1.0
info:
  title: Cubbo Clients API
  version: '1.0'
  summary: >-
    Orders, inventory, replenishments, returns, shipping and webhooks for Cubbo
    fulfillment.
  description: >
    The Cubbo Clients API connects your store, ERP or marketplace with Cubbo's
    fulfillment network.

    All endpoints except `POST /auth/token` require a bearer token; see the
    Authentication guide.

    Request and response bodies are JSON. Errors are JSON objects with an
    `error` key.
  contact:
    name: Cubbo integrations
    email: integraciones@cubbo.com
servers:
  - url: https://api.cubbo.com/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: Exchange client credentials for a bearer token.
  - name: Orders
    description: Create, update, hold, cancel and read sales orders.
  - name: Shipping labels
    description: Read the shipping labels generated for an order.
  - name: Inventory
    description: Products and stock per store.
  - name: Lots
    description: Lot-level inventory for products with expiration or batch tracking.
  - name: Reports
    description: Bulk reports for reconciliation.
  - name: Replenishments
    description: Inbound shipments to the warehouse.
  - name: Returns
    description: Returns and exchanges.
  - name: Stores
    description: Store provisioning and settings.
  - name: Shipping methods
    description: Available shipping methods, coverage and quotes.
  - name: Click and collect
    description: Pickup points and in-store pickup orders.
paths:
  /products/{id}:
    patch:
      tags:
        - Inventory
      summary: Update a product
      description: >
        Updates the editable fields of one product: name, description, price,
        image, barcode, SKUs,

        weight and dimensions. Only the fields you send are changed; everything
        else is kept.

        - **SKU and barcode changes are blocked once the product has stock** in
        the warehouse (any unit, in any status). The whole request is rejected
        with 422 in that case, even if it also carries other fields.

        - `skus` **replaces** the product's full SKU list: existing SKUs are
        removed and the ones you send are added. An empty array is treated as
        "no change". The new SKUs must not be in use by another product of the
        store.

        - `bar_code` must be unique in the store and must not match a SKU of
        another product.

        - `weight` is stored in kilograms; send `weight_unit: "g"` (or `"gr"`)
        to send grams and have the value converted. `weight` must be greater
        than 0.

        - `length`, `width` and `height` must be between 0.01 and 999999.99.

        - Concurrent updates of the same product are serialized; a second
        simultaneous update receives `202 Accepted`.

        - The response is the full product in the same format the Cubbo app uses
        (see `ProductDetailed`).
      operationId: updateProduct
      parameters:
        - name: id
          in: path
          required: true
          description: >-
            Cubbo product id, as returned by `GET /inventory` or `POST
            /products`.
          schema:
            type: integer
          example: 12345
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProductUpdateRequest'
            examples:
              rename:
                value:
                  name: Widget Pro Black v2
                  description: <p>Updated description.</p>
                  price: 109.99
              logistics:
                value:
                  weight: 750
                  weight_unit: g
                  length: 12.5
                  width: 7
                  height: 3
                  dimension_unit: cm
              replaceSkus:
                value:
                  skus:
                    - SKU-RED-M
                    - SKU-RED-M-ALT
                  bar_code: '7501234567899'
      responses:
        '200':
          description: Product updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductDetailed'
              example:
                id: 12345
                name: Widget Pro Black v2
                billing_name: null
                description: <p>Updated description.</p>
                has_imei: false
                requires_unit_code: false
                allow_unit_code_substitution: false
                personalized_units: false
                is_fragile: false
                is_kit: false
                bar_code: '7501234567890'
                is_dropshipping: false
                has_expiration: true
                freshness: 180
                stock:
                  IN_WAREHOUSE: 250
                  AVAILABLE: 188
                  AVAILABLE_NOT_EXTERNALLY_CONFIRMED: 0
                  AVAILABLE_EXTERNALLY_CONFIRMED: 188
                  UNAVAILABLE: 22
                  RECEPTION-INCOMING-SELL-AHEAD: 0
                  INCOMING-SELL-AHEAD: 0
                  RESERVED-RECEPTION-INCOMING-SELL-AHEAD: 0
                  RESERVED-INCOMING-SELL-AHEAD: 0
                  DAMAGED: 2
                  RECEPTION: 0
                  OUT_OF_STOCK: 0
                  RESERVED: 40
                  RESERVED_BY_ORDERS: 40
                  RESERVED_BY_RETURNS: 0
                  ACTIVE: 188
                  RESERVED-WITHOUT-SELL-AHEAD: 40
                  EXPIRED: 20
                  HOLDED: 20
                  BUFFER_STOCK: 0
                full_name: Widget Pro Black v2
                is_scannable: true
                product_image_path: null
                price: '109.99'
                weight: 0.75
                weight_unit: kg
                origin: NATIONAL
                buffer_stock: null
                is_packageless: false
                length: '12.5'
                width: '7.0'
                height: '3.0'
                dimension_unit: cm
                is_discarded: false
                product_codes:
                  - id: 9001
                    product_id: 12345
                    sku: SKU-RED-M
                    created_at: '2026-10-12T15:04:05.000Z'
                    updated_at: '2026-10-12T15:04:05.000Z'
                kit_childs: []
                store:
                  id: 1234
                  name: Example Store
                ncm_configuration: null
        '202':
          description: >-
            Another update of this product is still being processed. Retry
            later.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcceptedProcessing'
              example:
                message: >-
                  Accepted, another update for product 12345 is still
                  processing.
                transaction_id: 7f3c2a1e-0000-4000-8000-000000000000
                transaction_key: api_update_product-12345
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: No product with this id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Product not found
        '422':
          description: Validation or business error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                hasStock:
                  value:
                    error: 'Cannot change SKU or bar_code: product already has stock'
                blankName:
                  value:
                    error: Parameter name cannot be blank
                weightNotPositive:
                  value:
                    error: Parameter weight cannot be less than 0.01
                dimensionOutOfRange:
                  value:
                    error: Parameter length cannot be less than 0.01
                dimensionUnit:
                  value:
                    error: >-
                      Parameter dimension_unit must be within ["cm", "mm", "in",
                      "m"]
                skuTaken:
                  value:
                    error: Products [12346] with same Sku SKU-RED-M
                upcTaken:
                  value:
                    error: >-
                      Validation failed: Bar code upc 7501234567890 is already
                      taken for this store.
                imageIncomplete:
                  value:
                    error: Parameter base64_data is required
                imageTooLarge:
                  value:
                    error: >-
                      product_image.base64_data exceeds maximum allowed size
                      (10485760 bytes).
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - bearerAuth: []
components:
  schemas:
    ProductUpdateRequest:
      type: object
      description: >-
        Body of `PATCH /products/{id}`. Every field is optional; only the fields
        sent are changed.
      properties:
        name:
          type: string
          description: New product name. Must not be blank.
          example: Widget Pro Black v2
        description:
          type: string
          description: New description; HTML is allowed.
          example: <p>Updated description.</p>
        bar_code:
          type: string
          description: >-
            New barcode (UPC/EAN). Must be unique within the store. Rejected
            when the product has stock.
          example: '7501234567899'
        price:
          type: number
          description: >-
            New unit price. Up to 8 significant digits. A non-numeric value is
            stored as 0.
          example: 109.99
        skus:
          type: array
          description: >-
            Replaces the full SKU list. Rejected when the product has stock. An
            empty array is ignored.
          items:
            type: string
          example:
            - SKU-RED-M
            - SKU-RED-M-ALT
        product_image:
          $ref: '#/components/schemas/ProductImageInput'
        weight:
          type: number
          description: >-
            New unit weight, in `weight_unit`. Stored in kilograms. Must be at
            least 0.01.
          minimum: 0.01
          example: 750
        weight_unit:
          type: string
          description: >-
            Unit of `weight`. `g` or `gr` is converted to kilograms; any other
            value is stored as sent.
          example: g
        length:
          type: number
          description: Package length in `dimension_unit`, between 0.01 and 999999.99.
          minimum: 0.01
          maximum: 999999.99
          example: 12.5
        width:
          type: number
          description: Package width in `dimension_unit`, between 0.01 and 999999.99.
          minimum: 0.01
          maximum: 999999.99
          example: 7
        height:
          type: number
          description: Package height in `dimension_unit`, between 0.01 and 999999.99.
          minimum: 0.01
          maximum: 999999.99
          example: 3
        dimension_unit:
          type: string
          description: Unit of the dimensions.
          enum:
            - cm
            - mm
            - in
            - m
          example: cm
    ProductDetailed:
      type: object
      description: >-
        Full product representation, as used by the Cubbo app. Returned by
        `PATCH /products/{id}` and, as an array, by `POST /products` with
        variants.
      properties:
        id:
          type: integer
          description: Cubbo product id.
          example: 12345
        name:
          type: string
          description: Product name.
          example: Widget Pro Black
        billing_name:
          type:
            - string
            - 'null'
          description: Name printed on invoices.
          example: null
        description:
          type:
            - string
            - 'null'
          description: Product description (may contain HTML).
          example: <p>A professional-grade widget.</p>
        has_imei:
          type: boolean
          description: Each unit is identified by an IMEI.
          example: false
        requires_unit_code:
          type: boolean
          description: Each unit is identified by a unique code (serial).
          example: false
        allow_unit_code_substitution:
          type: boolean
          description: >-
            A reserved unit may be swapped for another unit of the same product
            at picking.
          example: false
        personalized_units:
          type:
            - boolean
            - 'null'
          description: Units are personalized per order.
          example: false
        is_fragile:
          type: boolean
          description: Requires fragile handling.
          example: false
        is_kit:
          type: boolean
          description: The product is a kit (bundle).
          example: false
        bar_code:
          type:
            - string
            - 'null'
          description: Barcode (UPC/EAN).
          example: '7501234567890'
        is_dropshipping:
          type: boolean
          description: Fulfilled by dropshipping.
          example: false
        has_expiration:
          type:
            - boolean
            - 'null'
          description: Stock is tracked by lot with expiration dates.
          example: true
        freshness:
          type:
            - integer
            - 'null'
          description: Minimum shelf life in days at receiving.
          example: 180
        stock:
          oneOf:
            - $ref: '#/components/schemas/ProductStock'
            - type: 'null'
          description: >-
            Aggregate stock (without the `LOST` and by-source keys). Null for a
            product that has never had stock.
        full_name:
          type: string
          description: Product name including the parent name for variants.
          example: Widget Pro Black
        is_scannable:
          type: boolean
          description: Units can be scanned at picking.
          example: true
        product_image_path:
          type:
            - string
            - 'null'
          description: URL of the product image, when one is attached.
          example: null
        price:
          type:
            - string
            - 'null'
          description: Unit price, as a decimal string.
          example: '99.99'
        weight:
          type:
            - number
            - 'null'
          description: Unit weight in `weight_unit`.
          example: 0.5
        weight_unit:
          type:
            - string
            - 'null'
          description: Unit of `weight`.
          example: kg
        origin:
          type:
            - string
            - 'null'
          description: Brazil only. Fiscal origin of the goods.
          example: NATIONAL
        buffer_stock:
          type:
            - integer
            - 'null'
          description: Safety stock excluded from availability.
          example: null
        is_packageless:
          type: boolean
          description: Ships without additional packaging.
          example: false
        length:
          type:
            - string
            - 'null'
          description: Package length, as a decimal string.
          example: '10.0'
        width:
          type:
            - string
            - 'null'
          description: Package width, as a decimal string.
          example: '8.0'
        height:
          type:
            - string
            - 'null'
          description: Package height, as a decimal string.
          example: '5.0'
        dimension_unit:
          type: string
          description: Unit of the dimensions.
          enum:
            - cm
            - mm
            - in
            - m
          example: cm
        extipi:
          type: string
          description: Brazil only. IPI exception code. Present only when set.
          example: '001'
        fci_key:
          type: string
          description: Brazil only. FCI key. Present only when set.
          example: 00000000-0000-0000-0000-000000000000
        is_discarded:
          type: boolean
          description: The product has been removed from the catalog.
          example: false
        product_codes:
          type: array
          description: SKUs registered for the product, with timestamps.
          items:
            type: object
            properties:
              id:
                type: integer
                description: SKU record id.
                example: 9001
              product_id:
                type: integer
                description: Product id.
                example: 12345
              sku:
                type: string
                description: The SKU.
                example: SKU-RED-M
              created_at:
                type: string
                format: date-time
                description: When the SKU was registered.
                example: '2026-10-12T15:04:05.000Z'
              updated_at:
                type: string
                format: date-time
                description: Last change of the SKU.
                example: '2026-10-12T15:04:05.000Z'
        kit_childs:
          type: array
          description: Components of the kit. Empty unless `is_kit` is true.
          items:
            type: object
            properties:
              id:
                type: integer
                description: Kit component line id.
                example: 501
              quantity:
                type: integer
                description: Units of the component in one kit.
                example: 2
              price_per_item:
                type:
                  - string
                  - 'null'
                description: Price per component unit
                as a decimal string.: null
                example: '49.50'
              child_product:
                type:
                  - object
                  - 'null'
                description: >-
                  The component product (id, name, codes, stock and flags). Null
                  when it was removed from the catalog.
                additionalProperties: true
        store:
          type: object
          description: >-
            Store that owns the product. Carries the store's id and name plus
            its configuration fields.
          properties:
            id:
              type: integer
              description: Store id.
              example: 1234
            name:
              type: string
              description: Store name.
              example: Example Store
          additionalProperties: true
        ncm_configuration:
          type:
            - object
            - 'null'
          description: >-
            Brazil only. The NCM fiscal configuration linked to the product
            (`id`, `ncm`, `description` and the tax rates and CFOP codes used on
            the NF-e). Null when none is linked.
          additionalProperties: true
      required:
        - id
        - name
        - is_kit
        - product_codes
    AcceptedProcessing:
      type: object
      description: >-
        Returned with HTTP 202 when a concurrent request for the same resource
        is still being processed.
      properties:
        message:
          type: string
          description: Explains which request is still processing.
          example: Accepted, but PRODUCT whit skus SKU-RED-M still processing.
        transaction_id:
          type: string
          description: Id of the request already in progress.
          example: 7f3c2a1e-0000-4000-8000-000000000000
        transaction_key:
          type: string
          description: Concurrency key the two requests collided on.
          example: api_create_products-SKU-RED-M-1234
      required:
        - message
        - transaction_id
        - transaction_key
    Error:
      type: object
      description: Error body returned by every failed request.
      required:
        - error
      properties:
        error:
          type: string
          description: >-
            Human-readable description of the failure. For `401` responses it is
            always `Unauthorized`.
          example: Parameter store_id is required
        message:
          type: string
          description: >-
            Present on `401` responses only; the reason the request was
            rejected.
          example: invalid token
        code:
          type:
            - string
            - 'null'
          description: >-
            Stable machine-readable code, present on some order, return and
            replenishment errors.
          example: ORDER_ALREADY_EXISTS
        context:
          type:
            - object
            - 'null'
          description: >-
            Extra data about the failure when available, for example the id of
            the conflicting order.
          additionalProperties: true
          example:
            order_id: 987654
    ProductImageInput:
      type: object
      description: >-
        An image sent inline as base64. PNG or JPEG, at most 5 MB decoded; the
        base64 payload may not exceed 10485760 bytes.
      properties:
        filename:
          type: string
          description: File name with extension.
          example: widget.png
        base64_data:
          type: string
          description: >-
            Base64-encoded image bytes. A `data:image/png;base64,` prefix is
            accepted and stripped.
          example: >-
            iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
        content_type:
          type: string
          description: MIME type of the image.
          enum:
            - image/png
            - image/jpeg
          example: image/png
      required:
        - filename
        - base64_data
        - content_type
    ProductStock:
      type: object
      description: >-
        Aggregate stock counts of a product. All counts are units. Keys with a
        dash are returned exactly as written.
      properties:
        IN_WAREHOUSE:
          type: integer
          description: Units physically in the warehouse, in any status.
          example: 250
        AVAILABLE:
          type: integer
          description: >-
            Units you can sell now (active units minus buffer stock, plus
            sell-ahead units).
          example: 188
        AVAILABLE_NOT_EXTERNALLY_CONFIRMED:
          type: integer
          description: >-
            Available units from replenishments not yet confirmed by your system
            (relevant when your store only sells confirmed stock).
          example: 0
        AVAILABLE_EXTERNALLY_CONFIRMED:
          type: integer
          description: >-
            Available units from confirmed replenishments, plus sell-ahead
            units.
          example: 188
        UNAVAILABLE:
          type: integer
          description: >-
            Units present but not sellable (on hold, expired, damaged, in
            reception).
          example: 22
        RECEPTION-INCOMING-SELL-AHEAD:
          type: integer
          description: Sell-ahead units that arrived and are being received.
          example: 0
        INCOMING-SELL-AHEAD:
          type: integer
          description: Sell-ahead units still inbound.
          example: 0
        RESERVED-RECEPTION-INCOMING-SELL-AHEAD:
          type: integer
          description: Sell-ahead units in reception already reserved by orders.
          example: 0
        RESERVED-INCOMING-SELL-AHEAD:
          type: integer
          description: Inbound sell-ahead units already reserved by orders.
          example: 0
        DAMAGED:
          type: integer
          description: Units marked as damaged.
          example: 2
        RECEPTION:
          type: integer
          description: Units in the reception process, not yet put away.
          example: 0
        OUT_OF_STOCK:
          type: integer
          description: >-
            Units requested by orders that could not be reserved for lack of
            stock.
          example: 0
        RESERVED:
          type: integer
          description: Units reserved, by orders and by inbound returns.
          example: 40
        RESERVED_BY_ORDERS:
          type: integer
          description: Units reserved by open orders.
          example: 40
        RESERVED_BY_RETURNS:
          type: integer
          description: Units reserved by inbound returns.
          example: 0
        ACTIVE:
          type: integer
          description: Active (sellable, unreserved) units on the shelf.
          example: 188
        RESERVED-WITHOUT-SELL-AHEAD:
          type: integer
          description: Units reserved by orders, excluding sell-ahead reservations.
          example: 40
        EXPIRED:
          type: integer
          description: Units in expired lots.
          example: 20
        HOLDED:
          type: integer
          description: Units in lots on hold.
          example: 20
        BUFFER_STOCK:
          type: integer
          description: Safety stock configured for the product, excluded from `AVAILABLE`.
          example: 0
        LOST:
          type: integer
          description: Units marked as lost.
          example: 1
        DAMAGED_BY_SOURCE:
          type: object
          description: >-
            `DAMAGED` split by where the damage was found. Keys are
            `REPLENISHMENT`, `RETURN`, `STORAGE` or `UNKNOWN`; only sources with
            units appear.
          additionalProperties:
            type: integer
          example:
            STORAGE: 2
        LOST_BY_SOURCE:
          type: object
          description: >-
            `LOST` split by where the loss happened. Keys are `REPLENISHMENT`,
            `RETURN`, `STORAGE`, `DELIVERY` or `UNKNOWN`; only sources with
            units appear.
          additionalProperties:
            type: integer
          example:
            RETURN: 1
  responses:
    Unauthorized:
      description: >-
        Missing or invalid token, wrong credentials, or no access to the
        requested store.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            invalidToken:
              value:
                error: Unauthorized
                message: invalid token
            noHeader:
              value:
                error: Unauthorized
                message: no authorization header found
            storeNotAllowed:
              value:
                error: Unauthorized
                message: not allowed to show? this Store
    InternalServerError:
      description: >-
        Unexpected error. Retry with backoff; if it persists, send the timestamp
        to Cubbo support.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: 'unexpected error, timestamp: 1760000000'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Token returned by `POST /auth/token`, sent as `Authorization: Bearer
        <token>`.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.