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

# Update a digital product

> Partially updates a digital product. PATCH on the same path behaves identically.

Updates a digital product: send only the fields to change (at least one). `PATCH /digital-products/{id}` accepts the same body and behaves identically. Requires the `WRITE_INVENTORY` scope.

The pricing rules are re-checked on the merged product, so changing `access` to `both` also needs both prices. A price for a way of buying the product no longer offers is discarded.

<Note>
  Sending a `fileId` replaces the attached file and deletes the previous one from storage. An app cannot obtain a `fileId` (see [Create a digital product](/apps-api/endpoint/digital-products/create-digital-product)), so apps normally leave it out.
</Note>

<Note>
  These endpoints only work on a store whose type is `digital`. On any other store they return `403` with `This is only available on digital stores.` See [Digital stores](/digital-stores).
</Note>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT https://api.salesive.com/api/v1/digital-products/6702c1a4e1b3a40012cd2001 \
    -H "Authorization: Bearer app_<your-app-access-token>" \
    -H "Content-Type: application/json" \
    -d '{"pricing":{"oneTime":5000},"featured":true}'
  ```
</CodeGroup>


## OpenAPI

````yaml apps-api/specs/digital.json PUT /digital-products/{id}
openapi: 3.1.0
info:
  title: Salesive Apps API , Digital products
  description: >-
    Digital store endpoints (products, the all-access pass and buyer access)
    callable by an installed third-party app using its app access token. They
    only work on stores whose type is `digital`. The target store is bound to
    the token server-side by the OAuth install flow.
  version: 1.0.0
servers:
  - url: https://api.salesive.com/api/v1
    description: Production
security:
  - AppToken: []
paths:
  /digital-products/{id}:
    put:
      tags:
        - digital-products
      summary: Update a digital product
      description: >-
        Partially updates a digital product: send only the fields to change.
        `PATCH` on the same path accepts the same body and behaves identically.
        Sending a new `fileId` replaces the attached file and deletes the old
        one from storage (best effort). The pricing rules are checked on the
        merged product, so switching `access` to `both` needs both prices.
        Requires the `WRITE_INVENTORY` scope. The store must be a digital store,
        otherwise the call returns 403.
      operationId: updateDigitalProduct
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The digital product's ObjectId.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              minProperties: 1
              properties:
                name:
                  type: string
                  description: Product name (required, max 120 characters).
                description:
                  type: string
                  description: Description (max 10,000 characters).
                author:
                  type: string
                  description: Author or publisher (max 120 characters).
                images:
                  type: array
                  items:
                    type: string
                    format: uri
                  description: Cover image links (http or https, max 10).
                category:
                  type: string
                  nullable: true
                  description: >-
                    Category ObjectId, which must belong to this store. `null`
                    or an empty string clears it.
                access:
                  type: string
                  enum:
                    - purchase
                    - subscription
                    - both
                  description: How buyers get the product. Default `purchase`.
                pricing:
                  type: object
                  properties:
                    oneTime:
                      type: number
                      nullable: true
                      minimum: 0
                      description: >-
                        One-time price. Required (and above 0) when `access` is
                        `purchase` or `both`.
                    monthly:
                      type: number
                      nullable: true
                      minimum: 0
                      description: >-
                        Price for a 30-day pass. Required (and above 0) when
                        `access` is `subscription` or `both`.
                  description: >-
                    Prices in the store currency. A price for a way of buying
                    that `access` does not offer is discarded.
                inPass:
                  type: boolean
                  description: Include the product in the store's all-access pass.
                preview:
                  $ref: '#/components/schemas/DigitalPreview'
                fileId:
                  type: string
                  description: >-
                    Id of a private file already uploaded to the store's file
                    storage. See the note on this page: an app cannot upload
                    that file itself.
                listed:
                  type: boolean
                  description: >-
                    Show the product in the storefront. A product with no file
                    is saved unlisted, and asking to list it returns 400.
                featured:
                  type: boolean
              description: >-
                Any subset of the create fields. At least one is required. The
                pricing rules are re-checked on the merged product.
              example:
                pricing:
                  oneTime: 5000
                featured: true
      responses:
        '200':
          description: 'Update a digital product: success.'
          content:
            application/json:
              schema:
                type: object
                required:
                  - status
                  - success
                  - message
                  - data
                properties:
                  status:
                    type: integer
                    example: 200
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: Digital product updated successfully
                  data:
                    allOf:
                      - $ref: '#/components/schemas/DigitalProduct'
                    example:
                      _id: 6702c1a4e1b3a40012cd2001
                      shop: 66a1eee0e1b3a40012ab0001
                      name: The Lagos Cookbook
                      description: >-
                        120 everyday Nigerian recipes, with a shopping list for
                        each week.
                      author: Ngozi Okafor
                      images:
                        - https://cdn.salesive.com/d/lagos-cookbook-cover.jpg
                      category:
                        _id: 66a2a0aae1b3a40012cd0001
                        name: Cookbooks
                        slug: cookbooks
                      access: both
                      pricing:
                        oneTime: 5000
                        monthly: 1500
                      price: 1500
                      inPass: true
                      file:
                        name: lagos-cookbook.pdf
                        size: 8421376
                        format: pdf
                        mimetype: application/pdf
                        attached: true
                      preview:
                        enabled: true
                        pages: 3
                      listed: true
                      featured: true
                      createdAt: '2026-10-11T09:12:00.000Z'
                      updatedAt: '2026-10-11T09:30:00.000Z'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
components:
  schemas:
    DigitalPreview:
      type: object
      description: >-
        The free preview of a PDF book: the first `pages` pages, cut on demand.
        A product with no stored preview setting reads as `{ enabled: true,
        pages: 3 }`.
      properties:
        enabled:
          type: boolean
          description: Whether buyers can open the free preview. Default `true`.
        pages:
          type: integer
          minimum: 1
          maximum: 20
          description: >-
            How many pages to show, 1 to 20 (default 3). The storefront never
            shows more than half of the book. A value outside 1 to 20, or a
            fraction, returns 400 and nothing changes.
    DigitalProduct:
      type: object
      properties:
        _id:
          type: string
        shop:
          type: string
          description: The store id (always the installing store).
        name:
          type: string
          description: Product name (max 120 characters).
        description:
          type: string
          description: Description (max 10,000 characters).
        author:
          type: string
          description: Author or publisher (max 120 characters).
        images:
          type: array
          items:
            type: string
          description: Cover image links (max 10). The first is the main cover.
        category:
          description: >-
            Category. Populated as `{ _id, name, slug }` on reads, `null` when
            none.
          nullable: true
          oneOf:
            - type: string
              description: Category ObjectId.
            - type: object
              properties:
                _id:
                  type: string
                name:
                  type: string
                slug:
                  type: string
        access:
          type: string
          enum:
            - purchase
            - subscription
            - both
          description: >-
            How buyers get the product: `purchase` (one-time payment, permanent
            access), `subscription` (a 30-day pass for this product) or `both`
            (the buyer picks).
        pricing:
          type: object
          properties:
            oneTime:
              type: number
              nullable: true
              description: >-
                One-time price in the store currency. `null` unless `access` is
                `purchase` or `both`.
            monthly:
              type: number
              nullable: true
              description: >-
                Price for a 30-day pass. `null` unless `access` is
                `subscription` or `both`.
        price:
          type: number
          description: >-
            Derived, read-only: the cheapest way in (the lower of
            `pricing.oneTime` and `pricing.monthly`). Storefront cards show
            this.
        inPass:
          type: boolean
          description: Whether the product is covered by the store's all-access pass.
        file:
          type: object
          description: >-
            The private file buyers download. The file id is never returned:
            `attached` says whether one is set.
          properties:
            name:
              type: string
              description: Original file name.
            size:
              type: integer
              description: Size in bytes.
            format:
              type: string
              enum:
                - pdf
                - epub
                - mobi
                - zip
              nullable: true
            mimetype:
              type: string
            attached:
              type: boolean
              description: '`true` when a file is attached.'
        preview:
          $ref: '#/components/schemas/DigitalPreview'
        listed:
          type: boolean
          description: >-
            Whether the product shows in the storefront. A product without a
            file cannot be listed.
        featured:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
  responses:
    BadRequest:
      description: The body or query failed validation. `message` says which rule.
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: integer
                example: 400
              success:
                type: boolean
                example: false
              message:
                type: string
                example: A one-time price is required
              data:
                type: object
                nullable: true
    Unauthorized:
      description: Missing or invalid app access token.
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: integer
                example: 401
              success:
                type: boolean
                example: false
              message:
                type: string
                example: App token expired or invalid.
              data:
                type: object
                nullable: true
    Forbidden:
      description: >-
        The app token lacks the required scope (`READ_INVENTORY` for reads,
        `WRITE_INVENTORY` for writes), or the store is not a digital store
        (`This is only available on digital stores.`).
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: integer
                example: 403
              success:
                type: boolean
                example: false
              message:
                type: string
                example: >-
                  This app is missing the required permission(s):
                  WRITE_INVENTORY
              data:
                type: object
                nullable: true
    NotFound:
      description: The record does not exist in this store.
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: integer
                example: 404
              success:
                type: boolean
                example: false
              message:
                type: string
                example: Product not found
              data:
                type: object
                nullable: true
    Conflict:
      description: The request conflicts with the current state.
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: integer
                example: 409
              success:
                type: boolean
                example: false
              message:
                type: string
                example: That file is already attached to another product
              data:
                type: object
                nullable: true
  securitySchemes:
    AppToken:
      type: http
      scheme: bearer
      description: >-
        Installed-app access token (prefix app_), issued by the OAuth install
        flow. The store is bound to the token server-side , never send a shop
        id.

````

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