> ## 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.

# Create a lot or update its expiration date

> Creates a lot for a product, or updates the expiration date of an existing lot. The lot is
identified by its unique code inside the store, which is built as `<sku>-<lot_code>` when
`sku` is sent, or is exactly `lot_code` when it is not.
- If no lot with that code exists, `sku` is required and must belong to a product of the store; the lot is created with the given `expiration_date` (optional).
- If the lot exists, only `expiration_date` is updated, and only when you send one; omitting it leaves the stored date untouched.
- Moving the date into the future re-validates the lot shortly after the call: a lot that had been expired is reactivated, together with its stock units. Moving it into the past expires the lot.
- `expiration_date` in the response is returned as an ISO 8601 timestamp at UTC midnight of the stored date.
- `status` in the response is the lot status in lowercase (`active`, `holded`, `damaged`, `expired`).




## OpenAPI

````yaml /openapi.yaml post /lots/upsert
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:
  /lots/upsert:
    post:
      tags:
        - Lots
      summary: Create a lot or update its expiration date
      description: >
        Creates a lot for a product, or updates the expiration date of an
        existing lot. The lot is

        identified by its unique code inside the store, which is built as
        `<sku>-<lot_code>` when

        `sku` is sent, or is exactly `lot_code` when it is not.

        - If no lot with that code exists, `sku` is required and must belong to
        a product of the store; the lot is created with the given
        `expiration_date` (optional).

        - If the lot exists, only `expiration_date` is updated, and only when
        you send one; omitting it leaves the stored date untouched.

        - Moving the date into the future re-validates the lot shortly after the
        call: a lot that had been expired is reactivated, together with its
        stock units. Moving it into the past expires the lot.

        - `expiration_date` in the response is returned as an ISO 8601 timestamp
        at UTC midnight of the stored date.

        - `status` in the response is the lot status in lowercase (`active`,
        `holded`, `damaged`, `expired`).
      operationId: upsertLot
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LotUpsertRequest'
            examples:
              create:
                value:
                  store_id: 1234
                  sku: SKU-RED-M
                  lot_code: L2026-04
                  expiration_date: '2026-12-31'
              updateDate:
                value:
                  store_id: 1234
                  lot_code: SKU-RED-M-L2026-04
                  expiration_date: '2027-01-15'
      responses:
        '200':
          description: Lot created or updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LotUpsertResponse'
              example:
                id: 987
                unique_code: SKU-RED-M-L2026-04
                expiration_date: '2026-12-31T00:00:00Z'
                status: active
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          description: Validation or business error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missingLotCode:
                  value:
                    error: Parameter lot_code is required
                missingStoreId:
                  value:
                    error: Parameter store_id is required
                badDate:
                  value:
                    error: '''31/31/2026'' is not a valid Date'
                skuRequiredOnCreate:
                  value:
                    error: sku is required when creating a new lot
                productNotFound:
                  value:
                    error: No product found with sku SKU-RED-M in store 1234
                storeNotFound:
                  value:
                    error: Couldn't find Store with 'id'=1234
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
        - bearerAuth: []
components:
  schemas:
    LotUpsertRequest:
      type: object
      description: Body of `POST /lots/upsert`.
      properties:
        store_id:
          type: integer
          description: Store the lot belongs to.
          example: 1234
        sku:
          type: string
          description: >-
            SKU of the product. Required when creating a lot. When sent, the
            lot's unique code becomes `<sku>-<lot_code>`.
          example: SKU-RED-M
        lot_code:
          type: string
          description: Lot code. Used as the full unique code when `sku` is omitted.
          example: L2026-04
        expiration_date:
          type: string
          format: date
          description: >-
            Expiration date (`YYYY-MM-DD`). Optional; when omitted on an
            existing lot the stored date is kept.
          example: '2026-12-31'
      required:
        - store_id
        - lot_code
    LotUpsertResponse:
      type: object
      description: The lot after the upsert.
      properties:
        id:
          type: integer
          description: Lot id.
          example: 987
        unique_code:
          type: string
          description: The lot's unique code within the store.
          example: SKU-RED-M-L2026-04
        expiration_date:
          type:
            - string
            - 'null'
          format: date-time
          description: Expiration date as an ISO 8601 timestamp at UTC midnight, or null.
          example: '2026-12-31T00:00:00Z'
        status:
          type: string
          description: Lot status, in lowercase.
          enum:
            - active
            - holded
            - damaged
            - expired
          example: active
      required:
        - id
        - unique_code
        - expiration_date
        - status
    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
  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.