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

# Add, change or remove some of a collection version's content cards

> Merges changes into one collection version's content cards: cards the body does not name are left exactly as they are. Read the cards first with `GET /brand-features/{collection_id}`, then send each card you change whole, as GET returned it with only your change applied: a field left out is cleared. A handle of this version's cards updates that card in place; a card without a handle is created and placed first. A handle that belongs to a card outside this collection version is refused (409). `delete_handles` removes cards from this version. Versions of a collection can share a card, so an update shows in every version that lists it. Send one PATCH at a time per collection: a PATCH that races another is refused (409) and must be retried from a fresh GET. Media must be existing Shopify file gids (for example one another card uses); uploading new images or videos is not available. Side effects: Shopify metaobject writes, live on the storefront at once when the version is the collection's published one. Returns the version's resulting cards in GET's shape, including generated handles. Give each new card a `handle` of your own (lowercase letters, digits, `-`, `_`), so resending a PATCH whose answer you lost updates the card instead of creating it twice.



## OpenAPI

````yaml /api-reference/openapi/lite.json patch /brand-features/{collection_id}
openapi: 3.1.0
info:
  title: Search & Merchandising API
  version: 1.0.0
  description: >-
    REST API behind Depict: Search & Merchandising, the native Shopify app:
    onboarding, collections, boost & bury, dashboards, A/B testing and
    multi-store management. Endpoints are served under the /api/lite prefix and
    are authenticated with the Shopify session token that App Bridge issues to
    the embedded app.
servers:
  - url: /api/lite
security:
  - ShopifySessionToken: []
paths:
  /brand-features/{collection_id}:
    patch:
      summary: Add, change or remove some of a collection version's content cards
      description: >-
        Merges changes into one collection version's content cards: cards the
        body does not name are left exactly as they are. Read the cards first
        with `GET /brand-features/{collection_id}`, then send each card you
        change whole, as GET returned it with only your change applied: a field
        left out is cleared. A handle of this version's cards updates that card
        in place; a card without a handle is created and placed first. A handle
        that belongs to a card outside this collection version is refused (409).
        `delete_handles` removes cards from this version. Versions of a
        collection can share a card, so an update shows in every version that
        lists it. Send one PATCH at a time per collection: a PATCH that races
        another is refused (409) and must be retried from a fresh GET. Media
        must be existing Shopify file gids (for example one another card uses);
        uploading new images or videos is not available. Side effects: Shopify
        metaobject writes, live on the storefront at once when the version is
        the collection's published one. Returns the version's resulting cards in
        GET's shape, including generated handles. Give each new card a `handle`
        of your own (lowercase letters, digits, `-`, `_`), so resending a PATCH
        whose answer you lost updates the card instead of creating it twice.
      operationId: contentCardsPatch
      parameters:
        - schema:
            type: string
            description: The Shopify collection id (numeric, no gid prefix).
          required: true
          description: The Shopify collection id (numeric, no gid prefix).
          name: collection_id
          in: path
        - schema:
            type: string
            description: Lite merchant id, e.g. `shopify-<shop id>`.
          required: true
          description: Lite merchant id, e.g. `shopify-<shop id>`.
          name: merchant_id
          in: query
        - schema:
            type: string
            format: uuid
            description: The collection version (UUID) the features belong to.
          required: true
          description: The collection version (UUID) the features belong to.
          name: version
          in: query
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContentCardsPatch'
      responses:
        '200':
          description: Saved; the version's cards after the change.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContentCardsPatchResult'
        '400':
          description: >-
            The query or body failed the schema (e.g. a card without
            `content.type`), a handle appears twice, a `delete_handles` entry is
            not a card of this version, or the merchant has no Shopify
            configuration.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Detail'
        '401':
          description: Not authenticated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Detail'
        '403':
          description: Authenticated, but this identity may not call the API.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Detail'
        '404':
          description: >-
            Merchant not found for this caller, or the collection has no such
            version.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Detail'
        '409':
          description: >-
            An upsert handle belongs to a card outside this collection version,
            or the version's cards changed while the PATCH ran (read them again
            and retry; its updates to existing cards may already be applied, the
            cards it created are not).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Detail'
        '415':
          description: Content-Type is not application/json.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Detail'
        '500':
          description: Internal error, or a Shopify write failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Detail'
components:
  schemas:
    ContentCardsPatch:
      type: object
      properties:
        upsert:
          type: array
          items:
            $ref: '#/components/schemas/ContentCardUpsert'
          default: []
          description: >-
            Cards to create or update. Each is written whole: send the complete
            card as GET returned it with your change applied (omitting `link`,
            `text`, `hover_image` or `visibility` clears it). Read-only fields
            such as `metaobject_id` are ignored.
        delete_handles:
          type: array
          items:
            type: string
            pattern: ^[a-z0-9_-]+$
          default: []
          description: >-
            Handles of this version's cards to remove from it. The card itself
            is deleted unless another version of the collection still lists it.
    ContentCardsPatchResult:
      allOf:
        - $ref: '#/components/schemas/ContentCards'
        - type: object
          properties:
            reread_failed:
              type: boolean
              enum:
                - true
              description: >-
                Present when the save succeeded but reading the cards back
                failed: `cards` then holds only the cards this PATCH wrote, as
                sent, with their handles and ids. Do not resend the PATCH; GET
                the version for its full list.
    Detail:
      type: object
      properties:
        detail:
          type: string
      required:
        - detail
      description: 'Every 4xx/5xx body: `{detail}`.'
    ContentCardUpsert:
      type: object
      properties:
        handle:
          type: string
          pattern: ^[a-z0-9_-]+$
          description: >-
            Which card to write. A handle of this version's cards updates that
            card in place; omit it (or use a new one) to create a card, which is
            placed first in the version's list. Lowercase letters, digits, `-`
            and `_` only.
        index:
          type: integer
          description: The grid slot the card is placed at (0 = first).
        span_rows:
          type: integer
          description: Grid rows the card covers.
        span_columns:
          type: integer
          description: Grid columns the card covers.
        aspect_ratio:
          type: number
          description: The card's aspect ratio, as the editor stores it.
        visibility:
          type:
            - string
            - 'null'
          enum:
            - desktop
            - mobile
            - null
          description: Show on one breakpoint only; omit to show on both.
        content:
          oneOf:
            - $ref: '#/components/schemas/ContentCardImage'
            - $ref: '#/components/schemas/ContentCardVideo'
            - $ref: '#/components/schemas/ContentCardSpace'
            - $ref: '#/components/schemas/ContentCardInstagramImage'
            - $ref: '#/components/schemas/ContentCardInstagramVideo'
          discriminator:
            propertyName: type
            mapping:
              image:
                $ref: '#/components/schemas/ContentCardImage'
              video:
                $ref: '#/components/schemas/ContentCardVideo'
              space:
                $ref: '#/components/schemas/ContentCardSpace'
              instagram_image:
                $ref: '#/components/schemas/ContentCardInstagramImage'
              instagram_video:
                $ref: '#/components/schemas/ContentCardInstagramVideo'
          description: >-
            What the card shows; `type` is required. `image` and `video` take
            the gid of a file already in the store's Shopify Files
            (gid://shopify/MediaImage/… or gid://shopify/Video/…), for example
            one another card uses: uploading new media is not available here.
            `space` is a card with no media (text only, or an empty slot of
            `height` px). The Instagram types come from the editor's Instagram
            import; keep them as read.
        hover_image:
          oneOf:
            - $ref: '#/components/schemas/ContentCardImage'
            - $ref: '#/components/schemas/ContentCardInstagramImage'
            - type: 'null'
          description: Image swapped in on hover; omit for none.
        text:
          $ref: '#/components/schemas/ContentCardText'
        link:
          $ref: '#/components/schemas/ContentCardUpsertLink'
      required:
        - index
        - span_rows
        - span_columns
        - aspect_ratio
        - content
    ContentCards:
      type: object
      properties:
        version:
          type: string
          description: The collection version (UUID) the cards belong to.
        cards:
          type: array
          items:
            $ref: '#/components/schemas/ContentCard'
          description: >-
            The version's cards in stored order (when two cards claim the same
            grid slot, the earlier one wins).
      required:
        - version
        - cards
    ContentCardImage:
      type: object
      properties:
        type:
          type: string
          enum:
            - image
        gid:
          type: string
          description: Shopify GID.
        filename:
          type: string
          description: >-
            The media file's name, for display. Saves ignore it; omit it or echo
            what GET returned.
        alt_text:
          type:
            - string
            - 'null'
      required:
        - type
        - gid
    ContentCardVideo:
      type: object
      properties:
        type:
          type: string
          enum:
            - video
        gid:
          type: string
          description: Shopify GID.
        filename:
          type: string
          description: >-
            The media file's name, for display. Saves ignore it; omit it or echo
            what GET returned.
      required:
        - type
        - gid
    ContentCardSpace:
      type: object
      properties:
        type:
          type: string
          enum:
            - space
        height:
          type:
            - integer
            - 'null'
      required:
        - type
    ContentCardInstagramImage:
      type: object
      properties:
        type:
          type: string
          enum:
            - instagram_image
        gid:
          type: string
          description: Shopify GID.
        creator:
          type: string
        post_url:
          type: string
        post_id:
          type: string
        media_id:
          type: string
        alt_text:
          type:
            - string
            - 'null'
      required:
        - type
        - gid
        - creator
        - post_url
        - post_id
        - media_id
    ContentCardInstagramVideo:
      type: object
      properties:
        type:
          type: string
          enum:
            - instagram_video
        gid:
          type: string
          description: Shopify GID.
        creator:
          type: string
        post_url:
          type: string
        post_id:
          type: string
        media_id:
          type: string
      required:
        - type
        - gid
        - creator
        - post_url
        - post_id
        - media_id
    ContentCardText:
      type:
        - object
        - 'null'
      properties:
        header:
          $ref: '#/components/schemas/ContentCardTextProperties'
        body:
          $ref: '#/components/schemas/ContentCardTextProperties'
        horizontal_alignment:
          type:
            - string
            - 'null'
          enum:
            - start
            - center
            - end
            - null
        vertical_alignment:
          type:
            - string
            - 'null'
          enum:
            - start
            - center
            - end
            - null
        background_overlay:
          type:
            - string
            - 'null'
        overlay_style:
          type:
            - string
            - 'null'
          enum:
            - solid
            - gradient
            - null
        text_shadow:
          type:
            - boolean
            - 'null'
        gap:
          type:
            - string
            - 'null'
    ContentCardUpsertLink:
      type:
        - object
        - 'null'
      properties:
        type:
          type: string
          enum:
            - collection
            - page
            - product
            - article
            - url
        gid:
          type: string
          description: Shopify GID.
        handle:
          type: string
        url:
          type:
            - string
            - 'null'
          description: >-
            For `type: url`: the address (https://…, a relative path, mailto:,
            tel: or an app link such as whatsapp://). javascript:, data:,
            vbscript:, blob: and file: urls are refused, and so is a url that
            cannot be parsed, which GET can return as the editor saved it (such
            as `https://` alone): send null (or remove the link) to clear it.
        article_handle:
          type:
            - string
            - 'null'
      required:
        - type
        - gid
        - handle
    ContentCard:
      type: object
      properties:
        handle:
          type: string
          description: The card's handle, unique among the store's cards.
        index:
          type: integer
          description: The grid slot the card is placed at (0 = first).
        span_rows:
          type: integer
          description: Grid rows the card covers.
        span_columns:
          type: integer
          description: Grid columns the card covers.
        aspect_ratio:
          type: number
          description: The card's aspect ratio, as the editor stores it.
        visibility:
          type:
            - string
            - 'null'
          enum:
            - desktop
            - mobile
            - null
          description: Show on one breakpoint only; omit to show on both.
        content:
          oneOf:
            - $ref: '#/components/schemas/ContentCardImage'
            - $ref: '#/components/schemas/ContentCardVideo'
            - $ref: '#/components/schemas/ContentCardSpace'
            - $ref: '#/components/schemas/ContentCardInstagramImage'
            - $ref: '#/components/schemas/ContentCardInstagramVideo'
          discriminator:
            propertyName: type
            mapping:
              image:
                $ref: '#/components/schemas/ContentCardImage'
              video:
                $ref: '#/components/schemas/ContentCardVideo'
              space:
                $ref: '#/components/schemas/ContentCardSpace'
              instagram_image:
                $ref: '#/components/schemas/ContentCardInstagramImage'
              instagram_video:
                $ref: '#/components/schemas/ContentCardInstagramVideo'
          description: >-
            What the card shows; `type` is required. `image` and `video` take
            the gid of a file already in the store's Shopify Files
            (gid://shopify/MediaImage/… or gid://shopify/Video/…), for example
            one another card uses: uploading new media is not available here.
            `space` is a card with no media (text only, or an empty slot of
            `height` px). The Instagram types come from the editor's Instagram
            import; keep them as read.
        hover_image:
          oneOf:
            - $ref: '#/components/schemas/ContentCardImage'
            - $ref: '#/components/schemas/ContentCardInstagramImage'
            - type: 'null'
          description: Image swapped in on hover; omit for none.
        text:
          $ref: '#/components/schemas/ProContentBlockText'
        link:
          $ref: '#/components/schemas/ContentCardLink'
        metaobject_id:
          type: string
          description: 'Read-only: the card''s Shopify metaobject gid.'
        clicks_id:
          type: integer
          description: >-
            Read-only: the numeric metaobject id; equals content_block_id in GET
            /brand-features/content-block-clicks/{collection_id}.
        image_url:
          type: string
          description: >-
            Read-only: URL of the card's image (a video's preview frame); absent
            while the media processes.
        hover_image_url:
          type: string
          description: 'Read-only: URL of the hover image.'
      required:
        - handle
        - index
        - span_rows
        - span_columns
        - aspect_ratio
        - content
        - metaobject_id
        - clicks_id
    ContentCardTextProperties:
      type:
        - object
        - 'null'
      properties:
        html_tag:
          type: string
          enum:
            - p
            - h1
            - h2
            - h3
            - h4
            - h5
            - h6
        color_hex:
          type:
            - string
            - 'null'
        bold:
          type:
            - boolean
            - 'null'
        italic:
          type:
            - boolean
            - 'null'
        underline:
          type:
            - boolean
            - 'null'
        text:
          type:
            - string
            - 'null'
        translations:
          type:
            - object
            - 'null'
          additionalProperties:
            type: string
          description: Text per locale, keyed by locale code.
      required:
        - html_tag
    ProContentBlockText:
      type:
        - object
        - 'null'
      properties:
        header:
          $ref: '#/components/schemas/ContentBlockTextProperties'
        body:
          $ref: '#/components/schemas/ContentBlockTextProperties'
        horizontal_alignment:
          type:
            - string
            - 'null'
          enum:
            - start
            - center
            - end
            - null
        vertical_alignment:
          type:
            - string
            - 'null'
          enum:
            - start
            - center
            - end
            - null
        background_overlay:
          type:
            - string
            - 'null'
        overlay_style:
          type:
            - string
            - 'null'
          enum:
            - solid
            - gradient
            - null
        text_shadow:
          type:
            - boolean
            - 'null'
        gap:
          type:
            - string
            - 'null'
    ContentCardLink:
      type:
        - object
        - 'null'
      properties:
        type:
          type: string
          enum:
            - collection
            - page
            - product
            - article
            - url
        gid:
          type: string
          description: Shopify GID.
        handle:
          type: string
        url:
          type:
            - string
            - 'null'
        article_handle:
          type:
            - string
            - 'null'
        name:
          type: string
          description: >-
            Read-only: title of the linked collection, page or product. Absent
            when the target was deleted (the gid is kept).
      required:
        - type
        - gid
        - handle
    ContentBlockTextProperties:
      type:
        - object
        - 'null'
      properties:
        html_tag:
          type: string
        color_hex:
          type:
            - string
            - 'null'
        bold:
          type:
            - boolean
            - 'null'
        italic:
          type:
            - boolean
            - 'null'
        underline:
          type:
            - boolean
            - 'null'
        text:
          type:
            - string
            - 'null'
        translations:
          type:
            - object
            - 'null'
          additionalProperties:
            type: string
          description: Text per locale, keyed by locale code.
      required:
        - html_tag
  securitySchemes:
    ShopifySessionToken:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Shopify App Bridge session token of the embedded Depict: Search &
        Merchandising app. The shop in the token determines the merchant;
        merchant_id parameters must belong to that shop.

````