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

# Crear producto

> Crea un producto con su precio y disponibilidad en cada menú. Requiere edición de productos habilitada en la marca. Las imágenes, SEO y contenido enriquecido se editan después con PUT /ecommerce/products/{productId}.

**Cómo funcionan los menús y precios**

Un menú es una lista de precios: dice qué productos se venden y a qué precio. En el administrador se llama *menú* y en la API *precio*: cada menú es un registro de `GET /ecommerce/prices`, y su `_id` es el `menuId` que aparece en `menus` de cada producto. Una marca puede tener varios menús, por ejemplo uno general, uno para un local y uno de almuerzo.

**1. Cada pedido usa un solo menú.** Los menús no se mezclan: el cliente ve el precio y la disponibilidad que el producto tiene en el menú que se está usando.

**2. Cómo se elige el menú en la tienda online.** Se revisan los menús habilitados de mayor a menor `priority` y se usa el primero que cumple todas estas condiciones:

- `storesIds` está vacío o incluye el local del pedido. Mientras no se sepa el local, los menús con locales no aplican.
- `channels` está vacío o incluye el canal del pedido. Si el cliente aún no elige cómo recibir el pedido, se considera delivery.
- `schedule` está abierto a la hora de entrega menos el tiempo de preparación del local, o ahora si el pedido no es programado. El horario solo restringe si `availableAtPeriods` es `true`; si no, el menú aplica a toda hora, salvo los días cerrados (`closedDays`).
- Faltan al menos `daysBefore` días de calendario para esa fecha.
- `segmentIds` está vacío, o el cliente inició sesión y pertenece a alguna de esas audiencias.

Si ningún menú cumple, se usa el menú por defecto (`isDefault`), aunque no cumpla sus condiciones. Si la marca no tiene menú por defecto, se usa el de mayor `priority`. Si la marca tiene un solo menú habilitado, se usa siempre.

**3. Productos no disponibles.** Si el producto no está disponible en el menú que se usa, no aparece en la tienda. Si en el administrador tiene un mensaje de no disponible, aparece con ese mensaje, pero no se puede comprar. Un producto tampoco aparece si tiene un modificador obligatorio sin opciones disponibles en ese menú. Agotado (`out-of-stock`) es otra cosa: se marca por local, y el producto aparece como agotado, salvo que la marca active *Ocultar productos no disponibles o sin stock*: entonces los agotados no aparecen.

**4. Cada menú tiene su propio precio.** Cambiar el precio en un menú no cambia los demás. Para cambiarlo en toda la marca, cámbialo en cada menú donde el producto está disponible. Para cambiarlo solo en un local, canal u horario, usa el punto 2 para saber qué menú se usa ahí.

**5. Descuentos.** `discountPrice` es el precio final que paga el cliente, no un monto ni un porcentaje, y no puede ser mayor que el precio: si bajas `price` por debajo del descuento guardado, envía también `discountPrice`. Si es menor que el precio, la tienda muestra el precio normal tachado. En las respuestas viene como `discount`. Enviar `discountPrice` deja un solo descuento, y `null` lo quita. En el administrador se pueden guardar varios descuentos seguidos: en ese caso `discount` es el primero, pero el cliente paga el último.

**6. Los cambios no son instantáneos.** La tienda se actualiza en segundo plano, y el menú elegido para cada cliente se guarda hasta 15 minutos, así que un cambio en las condiciones de un menú puede tardar ese tiempo en verse.



## OpenAPI

````yaml post /ecommerce/products
openapi: 3.1.0
info:
  title: Justo API
  version: 3.0.0
servers:
  - url: https://api.service.getjusto.com/v3
    description: Production server
security: []
paths:
  /ecommerce/products:
    post:
      summary: Create product
      description: >-
        Crea un producto con su precio y disponibilidad en cada menú. Requiere
        edición de productos habilitada en la marca. Las imágenes, SEO y
        contenido enriquecido se editan después con PUT
        /ecommerce/products/{productId}.


        **Cómo funcionan los menús y precios**


        Un menú es una lista de precios: dice qué productos se venden y a qué
        precio. En el administrador se llama *menú* y en la API *precio*: cada
        menú es un registro de `GET /ecommerce/prices`, y su `_id` es el
        `menuId` que aparece en `menus` de cada producto. Una marca puede tener
        varios menús, por ejemplo uno general, uno para un local y uno de
        almuerzo.


        **1. Cada pedido usa un solo menú.** Los menús no se mezclan: el cliente
        ve el precio y la disponibilidad que el producto tiene en el menú que se
        está usando.


        **2. Cómo se elige el menú en la tienda online.** Se revisan los menús
        habilitados de mayor a menor `priority` y se usa el primero que cumple
        todas estas condiciones:


        - `storesIds` está vacío o incluye el local del pedido. Mientras no se
        sepa el local, los menús con locales no aplican.

        - `channels` está vacío o incluye el canal del pedido. Si el cliente aún
        no elige cómo recibir el pedido, se considera delivery.

        - `schedule` está abierto a la hora de entrega menos el tiempo de
        preparación del local, o ahora si el pedido no es programado. El horario
        solo restringe si `availableAtPeriods` es `true`; si no, el menú aplica
        a toda hora, salvo los días cerrados (`closedDays`).

        - Faltan al menos `daysBefore` días de calendario para esa fecha.

        - `segmentIds` está vacío, o el cliente inició sesión y pertenece a
        alguna de esas audiencias.


        Si ningún menú cumple, se usa el menú por defecto (`isDefault`), aunque
        no cumpla sus condiciones. Si la marca no tiene menú por defecto, se usa
        el de mayor `priority`. Si la marca tiene un solo menú habilitado, se
        usa siempre.


        **3. Productos no disponibles.** Si el producto no está disponible en el
        menú que se usa, no aparece en la tienda. Si en el administrador tiene
        un mensaje de no disponible, aparece con ese mensaje, pero no se puede
        comprar. Un producto tampoco aparece si tiene un modificador obligatorio
        sin opciones disponibles en ese menú. Agotado (`out-of-stock`) es otra
        cosa: se marca por local, y el producto aparece como agotado, salvo que
        la marca active *Ocultar productos no disponibles o sin stock*: entonces
        los agotados no aparecen.


        **4. Cada menú tiene su propio precio.** Cambiar el precio en un menú no
        cambia los demás. Para cambiarlo en toda la marca, cámbialo en cada menú
        donde el producto está disponible. Para cambiarlo solo en un local,
        canal u horario, usa el punto 2 para saber qué menú se usa ahí.


        **5. Descuentos.** `discountPrice` es el precio final que paga el
        cliente, no un monto ni un porcentaje, y no puede ser mayor que el
        precio: si bajas `price` por debajo del descuento guardado, envía
        también `discountPrice`. Si es menor que el precio, la tienda muestra el
        precio normal tachado. En las respuestas viene como `discount`. Enviar
        `discountPrice` deja un solo descuento, y `null` lo quita. En el
        administrador se pueden guardar varios descuentos seguidos: en ese caso
        `discount` es el primero, pero el cliente paga el último.


        **6. Los cambios no son instantáneos.** La tienda se actualiza en
        segundo plano, y el menú elegido para cada cliente se guarda hasta 15
        minutos, así que un cambio en las condiciones de un menú puede tardar
        ese tiempo en verse.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/apiProductCreateInput'
      responses:
        '200':
          description: The OpenAPI spec
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    $ref: '#/components/schemas/apiListingProduct'
        '400':
          description: Errors
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: 'false'
                  error:
                    type: object
                    properties:
                      error:
                        type: string
                        example: error
                      message:
                        type: string
                        example: The request has an error
components:
  schemas:
    apiProductCreateInput:
      type: object
      description: >-
        Datos del producto nuevo. Sin menus, el producto se crea sin precio y no
        se muestra en la tienda. Los menús y sus IDs están en GET
        /ecommerce/prices.
      required:
        - name
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 1
          description: Nombre visible del producto.
        internalName:
          type: string
          description: Nombre interno del producto.
        description:
          type: string
          description: Descripción visible del producto.
        externalId:
          type: string
          description: ID externo único en la marca.
        categoriesIds:
          type: array
          description: IDs Justo o externos de las categorías del producto.
          items:
            type: string
        modifiersIds:
          type: array
          description: IDs Justo o externos de los modificadores del producto.
          items:
            type: string
        menus:
          type: array
          description: >-
            Precio y disponibilidad en cada menú donde se venderá. Incluye todos
            los menús que pueden aplicar en los locales y canales donde debe
            aparecer.
          items:
            type: object
            required:
              - menuId
              - price
            additionalProperties: false
            properties:
              menuId:
                type: string
                description: ID Justo o externo del menú.
              price:
                type: number
                minimum: 0
                description: >-
                  Precio base en la moneda de la marca. 0 significa gratis. Es
                  obligatorio si el producto aún no tiene precio en ese menú.
              discountPrice:
                type:
                  - number
                  - 'null'
                minimum: 0
                description: >-
                  Precio con descuento: el precio final rebajado, menor o igual
                  al precio base. No es un monto ni un porcentaje. Reemplaza los
                  descuentos guardados en ese menú; null los quita. Si bajas
                  price por debajo del precio con descuento actual, envía
                  también discountPrice o null.
              available:
                type: boolean
                description: >-
                  Si el producto se vende en ese menú. Al asignar un precio en
                  un menú nuevo sin este campo, queda disponible.
      example:
        name: Torta de chocolate
        description: Porción individual.
        categoriesIds:
          - ID_CATEGORIA
        menus:
          - menuId: ID_PRECIO
            price: 4990
    apiListingProduct:
      type: object
      description: Producto del catálogo.
      properties:
        productId:
          type: string
          description: ID Justo del producto.
        importId:
          type: string
          description: ID de importación del producto.
        name:
          type: string
          description: Nombre del producto.
        internalName:
          type: string
          description: Nombre interno del producto.
        description:
          type: string
          description: Descripción visible del producto.
        seoTitle:
          type:
            - string
            - 'null'
          maxLength: 300
          description: >-
            Título SEO independiente del nombre. Null o texto vacío restaura el
            título automático.
        seoDescription:
          type:
            - string
            - 'null'
          maxLength: 1000
          description: >-
            Metadescripción independiente de la descripción. Null o texto vacío
            restaura el valor automático.
        seoImageURL:
          type:
            - string
            - 'null'
          maxLength: 2048
          description: >-
            URL absoluta http o https sin credenciales, para SEO y enlaces
            compartidos. Null o texto vacío restaura la imagen automática. No
            modifica la galería.
        richContent:
          type:
            - string
            - 'null'
          maxLength: 50000
          description: >-
            HTML sanitizado, disponible en GET individual y respuesta de PUT.
            Null elimina el contenido. Admite texto, imágenes, galerías, tablas
            y acordiones; elimina scripts, estilos y clases.
        richContentPosition:
          type:
            - string
            - 'null'
          enum:
            - beforeModifiers
            - afterModifiers
            - null
          description: >-
            Posición del contenido respecto a los modificadores. Null usa
            beforeModifiers.
        hasRichContent:
          type: boolean
          description: >-
            Indica si tiene contenido enriquecido. El listado omite el HTML;
            consulta el detalle para obtenerlo.
        url:
          type: string
          description: URL pública del producto.
        partialUrl:
          type: string
          description: Path público del producto.
        categoriesNames:
          type: array
          description: Nombres de categorías asociadas.
          items:
            type: string
        categoriesIds:
          type: array
          description: IDs de categorías asociadas.
          items:
            type: string
        modifiersIds:
          type: array
          description: IDs de modificadores asociados.
          items:
            type: string
        externalId:
          type: string
          description: ID externo configurado por la marca.
        metadata:
          type: object
          description: Metadata del item escrita por API v3.
          additionalProperties: true
        images:
          type: array
          description: URLs de imágenes del producto.
          items:
            type: string
        menus:
          type: array
          description: >-
            Precio y disponibilidad en cada menú. El cliente ve sólo los del
            menú que aplica en su pedido; ver GET /ecommerce/prices.
          items:
            type: object
            description: >-
              Precio y disponibilidad del item en un menú (precio). Viene una
              entrada por cada menú de la marca, también los deshabilitados. En
              las opciones de modificador solo vienen menuId, price y available.
            properties:
              menuId:
                type: string
                description: ID Justo del menú (_id en GET /ecommerce/prices).
              price:
                type: number
                description: >-
                  Precio base en este menú. Si el item no tiene configuración en
                  este menú, es 0 y available no viene.
              discount:
                type:
                  - number
                  - 'null'
                description: >-
                  Precio con descuento: el precio final rebajado, no un monto ni
                  un porcentaje. null si no tiene. Si en el administrador se
                  guardaron varios descuentos seguidos, es el primero, pero el
                  cliente paga el último.
              available:
                type: boolean
                description: >-
                  true si se vende en este menú. Si es false o no viene, no se
                  vende: el item no aparece mientras se use este menú, salvo que
                  tenga un mensaje de no disponible en el administrador;
                  entonces aparece con ese mensaje, pero no se puede comprar.
              externalId:
                type: string
                description: >-
                  ID externo del producto en este menú: el de reemplazo si se
                  configuró; si no, el externalId del producto.
            additionalProperties: true

````

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