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

# Entities

> The six objects Unif returns, field by field.

Six entities cover everything Unif models. Each one has a stable ID prefix, a set of attributes
and a `metrics` block measured over the period you request.

| Entity     | ID prefix | Search                                                                      | Detail                                                                 |
| ---------- | --------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| Shop       | `shp_`    | [`POST /shops/search`](/api-reference/shops/search-shops)                   | [`GET /shops/{id}`](/api-reference/shops/get-a-shop)                   |
| Product    | `prd_`    | [`POST /products/search`](/api-reference/products/search-products)          | [`GET /products/{id}`](/api-reference/products/get-a-product)          |
| Creator    | `crt_`    | [`POST /creators/search`](/api-reference/creators/search-creators)          | [`GET /creators/{id}`](/api-reference/creators/get-a-creator)          |
| Video      | `vid_`    | [`POST /videos/search`](/api-reference/videos/search-videos)                | [`GET /videos/{id}`](/api-reference/videos/get-a-video)                |
| Livestream | `liv_`    | [`POST /livestreams/search`](/api-reference/livestreams/search-livestreams) | [`GET /livestreams/{id}`](/api-reference/livestreams/get-a-livestream) |
| Category   | `cat_`    | [`GET /categories`](/api-reference/categories/list-categories)              | [`GET /categories/{id}`](/api-reference/categories/get-a-category)     |

***

## Shop

A storefront on a channel — the seller, not the brand. One brand can operate several shops across
markets, and each is a separate entity with its own ID.

**Attributes** — `name`, `handle`, `url`, `logo_url`, `seller_type`, `categories`, `rating`,
`reviews_count`, `products_count`, `opened_at`.

`seller_type` normalizes each channel's own seller taxonomy into `brand`, `reseller`,
`cross_border`, `local` or `unknown`. It is the fastest way to separate first-party brands from
resellers in a result set.

**Metrics** — `revenue`, `units_sold`, `avg_unit_price`, `revenue_growth_rate`,
`revenue_by_source`, `products_sold_count`, `creators_count`, `videos_count`, `livestreams_count`.

`revenue_by_source` is the shop's revenue split across selling surfaces, as ratios summing to 1:

```json theme={null}
"revenue_by_source": { "video": 0.62, "live": 0.24, "mall": 0.09, "search": 0.05 }
```

<Tip>
  That split is the most diagnostic field on a shop. A shop at 80% video is running an affiliate
  motion; a shop at 80% mall is winning on placement. They need entirely different competitive
  responses.
</Tip>

***

## Product

A listing sold by one shop in one market. The same physical item sold by two shops is two
products, because price, commission and performance all differ.

**Attributes** — `title`, `url`, `image_url`, `brand`, `shop`, `category`, `price`,
`commission_rate`, `rating`, `reviews_count`, `listed_at`.

`price` carries `current`, `min` and `max` — the observed range over the period, which is how you
detect discount-driven spikes.

**Metrics** — `revenue`, `units_sold`, `avg_sale_price`, `revenue_growth_rate`,
`revenue_by_source`, `creators_count`, `videos_count`, `livestreams_count`, `gpm`.

<Warning>
  `avg_sale_price` is revenue divided by units sold, so it reflects what buyers actually paid.
  It diverges from `price.current` during promotions — and that gap is usually the story.
</Warning>

***

## Creator

Someone who drives attributed sales. Ranked by what they sell, not by audience size.

**Attributes** — `name`, `handle`, `url`, `avatar_url`, `bio`, `followers`, `categories`,
`agency`.

`categories` is ordered by the creator's revenue share, not by self-declared niche. A creator who
posts about fitness but sells supplements shows up under supplements.

**Metrics** — `revenue`, `units_sold`, `gpm`, `avg_commission_rate`, `products_count`,
`shops_count`, `videos_count`, `livestreams_count`, `avg_views_per_video`, `engagement_rate`,
`follower_growth`.

<Tip>
  Sort creator searches by `gpm` rather than `revenue` when you are sourcing partners. Revenue
  favors whoever has the biggest audience; `gpm` favors whoever converts the audience they have.
</Tip>

***

## Video

Short-form content with products attached.

**Attributes** — `caption`, `url`, `cover_url`, `duration_seconds`, `published_at`, `creator`,
`products`.

**Metrics** — `views`, `likes`, `comments`, `shares`, `engagement_rate`, `revenue`, `units_sold`,
`gpm`.

Video metrics are lifetime-to-date rather than period-windowed: a video's view count is the total
it has accumulated. The `period` on a video **search** filters which videos are returned by
publish date; it does not slice their metrics.

***

## Livestream

One live selling session, from start to end.

**Attributes** — `title`, `url`, `cover_url`, `started_at`, `ended_at`, `duration_seconds`,
`creator`, `shop`, `products`.

**Metrics** — `revenue`, `units_sold`, `viewers`, `peak_concurrent_viewers`,
`avg_watch_seconds`, `likes`, `comments`, `gpm`.

Sessions appear once they end. A session in progress is not returned, because its metrics would
change under you between pages of the same result set.

***

## Category

A node in the normalized category tree. Category IDs are **channel-independent** — this is the
one entity whose IDs are shared rather than per-channel, which is what makes market sizing
portable.

**Attributes** — `name`, `parent_id`, `level`, `path`, `children`.

**Metrics** — `revenue`, `units_sold`, `avg_unit_price`, `revenue_growth_rate`, `shops_count`,
`products_count`, `creators_count`.

```bash theme={null}
curl "https://api.unif.dev/v1/categories?market=US&depth=2" \
  -H "Authorization: Bearer $UNIF_API_KEY"
```

<Note>
  Because `cat_` IDs are shared, a filter written as `"category_ids": ["cat_beauty_personal_care"]`
  keeps selecting beauty when you enable a second channel — even though that channel's own
  taxonomy is shaped differently.
</Note>

***

## References between entities

Nested entities are returned as compact references — an `id` plus enough to display it — never as
full records. A product carries a `shop` reference; a video carries a `creator` reference and a
list of `products`.

```json theme={null}
"shop": {
  "id": "shp_01k3m9x7v2q8r4t6y0b1n5d7fa",
  "name": "GlowLab",
  "url": "https://www.tiktok.com/shop/glowlab"
}
```

To expand one, call its detail endpoint with the ID. That keeps list responses predictable in
size, and it keeps credit cost proportional to what you actually asked for.
