---
title: "Cross-model catalog of paid packs"
method: GET
path: "/v1/private-content/packs"
tags: ["Private Content"]
---

# Cross-model catalog of paid packs

`GET /v1/private-content/packs`

Tabs: all (newest), recommended (models the user chats with first), most_liked, collection (purchased, requires auth).

## Query parameters

- `tab` 'all' | 'recommended' | 'most_liked' | 'collection'
- `search` string
- `modelId` string, uuid
- `page` number
- `pageSize` number

## Response `200`

- PrivateContentPacksResponseDto
  - `total` number, required
  - `pageSize` number, required
  - `page` number, required
  - `items` PrivateContentPackCardDto[], required
    - `contentId` string, required
    - `model` PrivateContentModelDto, required
      - `id` string, required
      - `name` string, required — Localized model name.
      - `slug` string, required — Also the source of the @handle on the client.
      - `avatarUrl` string
    - `title` string, nullable
    - `description` string, nullable
    - `price` number, required — Price in coins.
    - `photosCount` number, required
    - `videosCount` number, required
    - `totalVideoDurationSec` number, required — Summed duration of every video in the pack.
    - `positiveRatePercent` number, nullable — Null until the pack has at least one reaction.
    - `likesCount` number, required — Synthetic baseline plus real likes. This — not the percentage — is what the catalog card renders.
    - `dislikesCount` number, required
    - `unlocksCount` number, required
    - `myReaction` 'LIKE' | 'DISLIKE', nullable
    - `coverUrl` string, nullable — Clean cover. Present only when the pack is unlocked.
    - `lockedCoverUrl` string, nullable — Pre-blurred 640px teaser cover, safe to serve while locked. Falls back to the nsfw thumbnail.
    - `previewVideoUrl` string, nullable — Tiny blurred clip to loop under the play badge. Present only while the pack is locked; null means the card keeps the still cover.
    - `previewVideoPosterUrl` string, nullable — First frame of the teaser, for the video poster.
    - `hasVideo` boolean, required — Whether to render a play badge on the cover.
    - `isExplicit` boolean, required
    - `isPurchased` boolean, required
    - `isLocked` boolean, required
    - `access` ModelContentPurchaseStateDto, required
      - `state` 'AUTH_REQUIRED' | 'SUBSCRIPTION_REQUIRED' | 'PURCHASE_REQUIRED' | 'UNLOCKED', required
      - `canPurchase` boolean, required
      - `isSubscribed` boolean, required
      - `isPurchased` boolean, required
      - `isLocked` boolean, required
      - `warning` string
    - `publishedAt` string, nullable
    - `purchasedAt` string, nullable — Only set in the collection tab.

---

[API](https://skmtc.dev/miaai/apis/backend-template-api.md) · [All operations](https://skmtc.dev/miaai/apis/backend-template-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/miaai/backend-template-api/revisions/2a8d88a5124f/schema)
