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

# Actualizar un producto por id

> Actualiza por el id que devolvió el upsert. Es la vía para **cambiarle el SKU** a un producto sin crear uno nuevo: el upsert resuelve por SKU, así que enviarle uno distinto crearía un segundo producto.

Una clave ausente deja el valor guardado como está, y un cuerpo que no cambia ningún campo responde `200` sin tocar nada — un sync idempotente puede reenviarlo.

De los atributos obligatorios sólo se revisan los que la solicitud **nombra**: uno que no mencionas pasa, y enviarlo en `null` (o en `""`) responde `422`, porque eso es pedir borrarlo.



## OpenAPI

````yaml /openapi.json patch /products/public/v1/{id}
openapi: 3.1.0
info:
  title: Revem API
  version: 1.0.0
  description: >-
    La API pública de Revem para integraciones de servidor a servidor:
    contactos, organizaciones, tickets y el canal de webchat. Se autentica con
    la API key de tu organización.
  contact:
    name: Soporte Revem
    email: soporte@revem.ai
    url: https://revem.ai
servers:
  - url: https://api.revem.ai
    description: Producción
security:
  - apiKey: []
tags:
  - name: Organizaciones
    description: >-
      Sincroniza empresas por identificador tributario, con atributos
      personalizados por nombre.
  - name: Contactos
    description: >-
      Sincroniza tu base de clientes con Revem. Los contactos se identifican por
      teléfono al crearlos y por id después.
  - name: Tickets
    description: Lee y actualiza los tickets de tu embudo desde tu sistema de gestión.
  - name: Webchat
    description: >-
      Conecta el chat de tu sitio con Revem: registra lo que escribe el
      visitante y lee las respuestas del equipo o del agente.
paths:
  /products/public/v1/{id}:
    patch:
      tags:
        - Productos
      summary: Actualizar un producto por id
      description: >-
        Actualiza por el id que devolvió el upsert. Es la vía para **cambiarle
        el SKU** a un producto sin crear uno nuevo: el upsert resuelve por SKU,
        así que enviarle uno distinto crearía un segundo producto.


        Una clave ausente deja el valor guardado como está, y un cuerpo que no
        cambia ningún campo responde `200` sin tocar nada — un sync idempotente
        puede reenviarlo.


        De los atributos obligatorios sólo se revisan los que la solicitud
        **nombra**: uno que no mencionas pasa, y enviarlo en `null` (o en `""`)
        responde `422`, porque eso es pedir borrarlo.
      operationId: updateProduct
      parameters:
        - name: id
          in: path
          required: true
          description: Id del producto en Revem.
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProductUpdateBody'
            example:
              price: 1390000
              Estado: Vendida
      responses:
        '200':
          description: Producto actualizado.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductUpdateResult'
              example:
                ok: true
                id: 3f2b6c1e-8d4a-4f0b-9c2e-7a1d5e6f8b90
                warnings: []
        '400':
          description: El id o el cuerpo no cumplen el esquema.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductsError'
        '401':
          description: Sin credencial, o la API key no existe o fue revocada.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthError'
              example:
                error: Unauthorized
                message: Invalid API key
        '403':
          description: >-
            La credencial no puede usar esta ruta. Una API key sólo alcanza los
            endpoints documentados aquí; cualquier otra ruta de la API responde
            este código.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthError'
              example:
                ok: false
                error: Forbidden
                message: This endpoint is not available to API keys
        '404':
          description: No hay un producto visible con ese id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductsError'
              example:
                ok: false
                error: Not Found
                message: No existe un producto con ese id
        '409':
          description: >-
            El SKU enviado ya pertenece a otro producto, o una integración
            administra la URL que se intenta escribir.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductsError'
              example:
                ok: false
                error: Conflict
                message: El SKU "CONT-20ST" ya pertenece a otro producto
        '422':
          description: >-
            Un atributo no existe, es ambiguo, es de sólo lectura, se intenta
            vaciar uno obligatorio o su valor no calza con el tipo.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductsError'
        '429':
          description: >-
            La key superó su límite de solicitudes por minuto. El header
            `retry-after` indica cuánto esperar.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
              example:
                ok: false
                error: Too many requests. Retry in 1 minute.
          headers:
            retry-after:
              description: Segundos que esperar antes de reintentar.
              schema:
                type: integer
            x-ratelimit-limit:
              description: Solicitudes permitidas por minuto.
              schema:
                type: integer
            x-ratelimit-remaining:
              description: Solicitudes que quedan en la ventana actual.
              schema:
                type: integer
            x-ratelimit-reset:
              description: Segundos hasta que la ventana se reinicia.
              schema:
                type: integer
components:
  schemas:
    ProductUpdateBody:
      type: object
      properties:
        sku:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            Identificador del producto en tu sistema. Único dentro del tenant;
            es la identidad con la que el upsert resuelve. Opcional: reemplaza
            el SKU actual. Si ya pertenece a otro producto responde 409.
        name:
          type: string
          minLength: 1
          maxLength: 500
          description: Nombre del producto, hasta 500 caracteres.
        description:
          type: string
          maxLength: 5000
          description: >-
            Descripción, hasta 5000 caracteres. Una cadena vacía no borra la
            descripción guardada.
        price:
          type: number
          minimum: 0
          maximum: 9999999999.99
          description: >-
            Precio, hasta dos decimales. Un tercer decimal responde 400 en vez
            de truncarse.
        currency:
          type: string
          pattern: ^[A-Za-z]{3}$
          description: Código de moneda de 3 letras, por ejemplo CLP.
        billing_frequency:
          type: string
          enum:
            - UNIQUE
            - WEEKLY
            - MONTHLY
            - QUARTERLY
            - SEMI_ANNUAL
            - ANNUAL
          description: >-
            UNIQUE, WEEKLY, MONTHLY, QUARTERLY, SEMI_ANNUAL o ANNUAL. Al crear,
            si se omite, queda en UNIQUE.
        billing_model:
          type: string
          enum:
            - UNIQUE
            - RECURRENT
          description: UNIQUE para un cobro único o RECURRENT para uno recurrente.
        unit_of_measurement:
          type: string
          enum:
            - UNIT
            - HOUR
            - DAY
            - MONTH
            - KG
            - G
            - LITER
            - METER
            - M2
          description: UNIT, HOUR, DAY, MONTH, KG, G, LITER, METER o M2.
        maximum_percentage_discount:
          type: integer
          minimum: 0
          maximum: 100
          description: Descuento máximo permitido, entero de 0 a 100.
        tax:
          type: integer
          minimum: 0
          maximum: 100
          description: Impuesto aplicable, entero de 0 a 100.
        active:
          type: boolean
          description: >-
            Si el producto está disponible. Esta API no borra productos: dar de
            baja es enviar active: false.
        media_url:
          type: string
          maxLength: 2000
          description: >-
            Enlace http o https a la imagen. Responde 409 si la administra la
            integración que importó el producto.
        external_url:
          type: string
          maxLength: 2000
          description: >-
            Enlace http o https donde se ve o se compra. Responde 409 si la
            administra la integración que importó el producto.
      additionalProperties: true
      description: >-
        Todos los campos son opcionales y una clave ausente deja el valor
        guardado como está. Los atributos personalizados van al mismo nivel que
        los campos fijos, identificados por su nombre en Revem (sin distinguir
        mayúsculas). Tienen que estar definidos para productos: un nombre sin
        definición responde 422 con la lista en unknownAttributes, y un valor
        que no calza con el tipo declarado —o una opción que no está en un
        select— también responde 422. Un null quita el atributo. Hasta 100
        atributos por solicitud.
    ProductUpdateResult:
      type: object
      properties:
        ok:
          type: boolean
          const: true
        id:
          type: string
          format: uuid
          description: ID del producto actualizado.
        warnings:
          type: array
          items:
            type: string
          description: Avisos que no impidieron la escritura. Hoy siempre vacío.
      required:
        - ok
        - id
        - warnings
      additionalProperties: false
      example:
        ok: true
        id: 3f2b6c1e-8d4a-4f0b-9c2e-7a1d5e6f8b90
        warnings: []
    ProductsError:
      type: object
      properties:
        ok:
          type: boolean
          const: false
        error:
          type: string
          description: Etiqueta del error.
        message:
          type: string
          description: Explicación legible del problema.
        unknownAttributes:
          type: array
          items:
            type: string
          description: >-
            Presente en el 422 por atributos: los nombres desconocidos, de sólo
            lectura u obligatorios que faltan.
        missingAttributes:
          type: array
          items:
            type: string
      required:
        - error
      additionalProperties: false
    AuthError:
      type: object
      properties:
        ok:
          type: boolean
          const: false
          description: Presente sólo en el `403`.
        error:
          type: string
        message:
          type: string
      required:
        - error
        - message
    RateLimitError:
      type: object
      properties:
        ok:
          type: boolean
          const: false
        error:
          type: string
          description: Incluye cuánto esperar antes de reintentar.
      required:
        - ok
        - error
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        La API key de tu organización, con la forma `rvm_<prefijo>.<secreto>`,
        enviada como `Authorization: Bearer rvm_…`. Revem la emite y sólo se
        muestra una vez; si la pierdes se reemplaza, no se recupera.

````