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

# Actualizar un premio

> Reemplaza los datos de un premio. **No es un patch**: mandá siempre el premio completo.

Las ofertas se reconcilian por nivel: la oferta que ya cubría un `levelId` conserva su `productOfferId`, y las ofertas de niveles que no vengan en `offers` se eliminan. Lo mismo con `categoryIds`: las categorías que no vengan se desasocian.

Las opciones que la API pública no expone (mensaje post canje, restricción temporal, tope mensual de canjes, cupones de integración) se conservan como estaban.



## OpenAPI

````yaml /api-reference/openapi.json put /external/products/{id}
openapi: 3.0.0
info:
  title: API de Tienda de Puntos
  description: >-
    API pública de Tienda de Puntos. Permite sumar puntos por compra, consultar
    clientes, validar canjes y consumir cupones desde tu POS, ERP o e-commerce.


    Todas las llamadas se autentican con el header `x-api-key`.
  version: 0.0.1
  contact: {}
servers:
  - url: https://api.tiendadepuntos.com
    description: Producción
  - url: https://apidev.tiendadepuntos.com
    description: Desarrollo
security:
  - ApiKeyAuth: []
tags: []
paths:
  /external/products/{id}:
    put:
      tags:
        - Premios
      summary: Actualizar un premio
      description: >-
        Reemplaza los datos de un premio. **No es un patch**: mandá siempre el
        premio completo.


        Las ofertas se reconcilian por nivel: la oferta que ya cubría un
        `levelId` conserva su `productOfferId`, y las ofertas de niveles que no
        vengan en `offers` se eliminan. Lo mismo con `categoryIds`: las
        categorías que no vengan se desasocian.


        Las opciones que la API pública no expone (mensaje post canje,
        restricción temporal, tope mensual de canjes, cupones de integración) se
        conservan como estaban.
      operationId: ExternalProductCatalogController_update
      parameters:
        - name: id
          required: true
          in: path
          description: ID del premio en Tienda de Puntos.
          schema:
            type: integer
            example: 771
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateExternalProductDto'
      responses:
        '200':
          description: Premio actualizado.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  status:
                    type: integer
                    example: 200
                  message:
                    type: string
                    example: Request was successful
                  data:
                    $ref: '#/components/schemas/ExternalProductOutputDto'
                required:
                  - success
                  - status
                  - message
        '400':
          description: El cuerpo o los parámetros no pasaron la validación.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    example: 400
                  timestamp:
                    type: string
                    format: date-time
                    example: '2026-07-31T14:05:12.431Z'
                  path:
                    type: string
                    example: /external/tags/add
                  method:
                    type: string
                    example: POST
                  message:
                    type: string
                    example: Error de validación
                  errors:
                    type: array
                    nullable: true
                    items:
                      type: object
                  data:
                    type: object
                    nullable: true
        '404':
          description: >-
            Falta el header `x-api-key` (`Api Key is required`) o la API key no
            corresponde a ningún comercio (`Business not found`). También se usa
            cuando el recurso pedido no existe.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    example: 404
                  timestamp:
                    type: string
                    format: date-time
                    example: '2026-07-31T14:05:12.431Z'
                  path:
                    type: string
                    example: /external/tags/add
                  method:
                    type: string
                    example: POST
                  message:
                    type: string
                    example: Api Key is required
                  errors:
                    type: array
                    nullable: true
                    items:
                      type: object
                  data:
                    type: object
                    nullable: true
      security:
        - ApiKeyAuth: []
components:
  schemas:
    UpdateExternalProductDto:
      type: object
      properties:
        name:
          type: string
          description: Nombre del premio.
          example: Café gratis
        shortDescription:
          type: string
          description: >-
            Descripción corta. Es la que se ve en el listado de premios de la
            app.
          example: Café a elección
        description:
          type: string
          description: Descripción larga del premio.
          example: Un café de especialidad a elección.
        termsAndConditions:
          type: string
          description: Términos y condiciones del canje.
          example: Válido de lunes a viernes.
        image:
          type: string
          description: >-
            URL pública de la imagen del premio. Tienda de Puntos no descarga la
            imagen: guarda la URL tal cual. Si se omite, el premio queda sin
            imagen.
          example: https://mi-cdn.com/premios/cafe.png
        isEnabled:
          type: boolean
          description: >-
            Si es `false`, el premio no aparece en el catálogo ni se puede
            canjear. Si el stock arranca en `0`, el premio queda deshabilitado
            aunque mandes `true`.
          example: true
          default: true
        categoryIds:
          description: IDs de las categorías de premios del comercio a las que pertenece.
          example:
            - 7
          type: array
          items:
            type: number
        stock:
          description: >-
            Control de stock del premio. Si se omite, el premio queda sin
            control de stock.
          allOf:
            - $ref: '#/components/schemas/ExternalProductStockInputDto'
        maxPurchases:
          type: number
          description: >-
            Máximo de canjes por cliente a lo largo de la vida del premio.
            Omitilo (o mandá `null`) para no poner tope.
          example: 1
          nullable: true
        expirationTermInDays:
          type: number
          description: >-
            Días que tiene el cliente para usar el cupón de canje. Omitilo para
            que el canje no venza.
          example: 30
          nullable: true
        offers:
          description: >-
            Precio en puntos por nivel. Las ofertas de niveles que no vengan en
            el array se eliminan.
          type: array
          items:
            $ref: '#/components/schemas/ExternalProductOfferUpdateInputDto'
      required:
        - name
        - shortDescription
        - offers
    ExternalProductOutputDto:
      type: object
      properties:
        id:
          type: number
          description: ID del premio.
          example: 771
        name:
          type: string
          description: Nombre del premio.
          example: Café gratis
        description:
          type: string
          description: Descripción larga.
          example: Un café de especialidad a elección.
          nullable: true
        shortDescription:
          type: string
          description: Descripción corta.
          example: Café a elección
          nullable: true
        image:
          type: string
          description: URL de la imagen principal.
          example: https://tdp-products.s3.amazonaws.com/771.png
          nullable: true
        isEnabled:
          type: boolean
          description: Si está deshabilitado, no se puede canjear desde la API.
          example: true
        stock:
          $ref: '#/components/schemas/ExternalProductStockOutputDto'
        offers:
          description: >-
            Precio en puntos según el nivel del cliente. El `productOfferId` que
            se usa para canjear se obtiene de acá.
          type: array
          items:
            $ref: '#/components/schemas/ExternalProductOfferOutputDto'
        categories:
          type: array
          items:
            $ref: '#/components/schemas/ExternalProductCategoryOutputDto'
        maxPurchases:
          type: number
          description: Máximo de canjes por cliente. `null` si no hay tope.
          example: null
          nullable: true
        createdAt:
          format: date-time
          type: string
          example: '2026-02-14T12:30:00.000Z'
        updatedAt:
          format: date-time
          type: string
          example: '2026-06-01T09:15:00.000Z'
      required:
        - id
        - name
        - description
        - shortDescription
        - image
        - isEnabled
        - stock
        - offers
        - categories
        - createdAt
        - updatedAt
    ExternalProductStockInputDto:
      type: object
      properties:
        controlled:
          type: boolean
          description: >-
            Si es `false`, el premio no lleva control de stock (canjes
            ilimitados) y se ignora `available`.
          example: true
        available:
          type: number
          description: >-
            Unidades disponibles. Al llegar a `0`, Tienda de Puntos deshabilita
            el premio automáticamente.
          example: 12
          default: 0
      required:
        - controlled
    ExternalProductOfferUpdateInputDto:
      type: object
      properties:
        levelId:
          type: number
          description: >-
            Nivel al que aplica este precio. Los IDs salen de `GET
            /external/levels`. Omitilo (o mandá `null`) para que el precio
            aplique a los clientes sin nivel.
          example: 3
          nullable: true
        points:
          type: number
          description: >-
            Puntos que cuesta el premio para ese nivel. `0` lo convierte en
            premio gratis.
          example: 500
        productOfferId:
          type: number
          description: >-
            ID de una oferta existente, para conservarla tal cual. Si se omite,
            la oferta se reconcilia por `levelId`: se reutiliza el id de la
            oferta que ya cubría ese nivel.
          example: 4412
      required:
        - points
    ExternalProductStockOutputDto:
      type: object
      properties:
        controlled:
          type: boolean
          description: Indica si el comercio lleva control de stock sobre este premio.
          example: true
        available:
          type: number
          description: >-
            Unidades disponibles. Solo tiene sentido cuando `controlled` es
            `true`.
          example: 12
      required:
        - controlled
        - available
    ExternalProductOfferOutputDto:
      type: object
      properties:
        productOfferId:
          type: number
          description: >-
            ID de la oferta. Es el `productOfferId` que consume `POST
            /external/exchange/product`.
          example: 4412
        points:
          type: number
          description: Puntos que cuesta el premio para este nivel.
          example: 500
        levelId:
          type: number
          description: Nivel al que aplica el precio. `null` si aplica a todos.
          example: 3
          nullable: true
        levelName:
          type: string
          description: Nombre del nivel.
          example: Nivel 2
          nullable: true
      required:
        - productOfferId
        - points
        - levelId
        - levelName
    ExternalProductCategoryOutputDto:
      type: object
      properties:
        id:
          type: number
          example: 7
        name:
          type: string
          example: Cafetería
      required:
        - id
        - name
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        API key del comercio. Se genera desde el panel de Tienda de Puntos, en
        Configuración → Integraciones.

````