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

# Collections

A **collection** is a saved catalog scope: brands, websites, categories, and/or specific products. Create it once, then pass `config.collection_id` on search, browse, image search, find-products-in-image, and conversations.

Collections endpoints are **free**.

## Clause semantics

A collection is a list of **clauses**. Clauses are **ORed**. Inside a clause, each list (`brand_ids`, `website_ids`, `category_ids`) is **ORed**, and those lists are **ANDed** with each other. `product_ids` in the same clause also **AND** — they pin the clause to those products.

| Shape                            | Matches                                        |
| -------------------------------- | ---------------------------------------------- |
| One clause: Nike + running-shoes | Nike products in running shoes                 |
| Two clauses: Nike, then Adidas   | Nike **or** Adidas                             |
| One clause: Nike + `product_ids` | Only those products, and only if they are Nike |

Request `filters` on search/browse/conversation **narrow** the collection. They cannot widen it.

Caps: 100 clauses, 100 ids per list per clause, 500 `product_ids` across the whole collection.

## Create a collection

Resolve brand, website, and category ids first (those lookups are free), then create the collection.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { Channel3 } from "@channel3/sdk";

  const client = new Channel3();

  const brands = await client.brands.search({ query: "Nike" });
  const nikeId = brands.brands[0].id;

  const collection = await client.collections.create({
    name: "Nike running",
    clauses: [
      {
        brand_ids: [nikeId],
        category_ids: ["running-shoes"],
      },
    ],
  });

  console.log(collection.collection_id);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from channel3_sdk import Channel3

  client = Channel3()

  brands = client.brands.search(query="Nike")
  nike_id = brands.brands[0].id

  collection = client.collections.create(
      name="Nike running",
      clauses=[
          {
              "brand_ids": [nike_id],
              "category_ids": ["running-shoes"],
          }
      ],
  )

  print(collection.collection_id)
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.trychannel3.com/v1/collections \
    -H "x-api-key: $CHANNEL3_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Nike running",
      "clauses": [
        {
          "brand_ids": ["brand_nike_abc123"],
          "category_ids": ["running-shoes"]
        }
      ]
    }'
  ```
</CodeGroup>

`website_ids` accept merchant ids or domains (`nike.com`); domains are stored as merchant ids. You can create an empty collection (`clauses: []`) and add clauses later with PATCH.

Optional `user_id` scopes the collection to one end user. If you omit `x-user-id` on a later collection-scoped search, Channel3 uses that `user_id` for click attribution.

## Search, browse, and image search

Pass the id on `config.collection_id`. Browse does not need `filters.brand_ids` / `category_ids` / `website_ids` when a collection is set.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const results = await client.products.search({
    query: "trail runners",
    config: { collection_id: collection.collection_id },
  });

  const grid = await client.products.browse({
    config: { collection_id: collection.collection_id },
  });
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  results = client.products.search(
      query="trail runners",
      config={"collection_id": collection.collection_id},
  )

  grid = client.products.browse(
      config={"collection_id": collection.collection_id},
  )
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.trychannel3.com/v1/search \
    -H "x-api-key: $CHANNEL3_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "trail runners",
      "config": { "collection_id": "COLLECTION_ID" }
    }'
  ```
</CodeGroup>

The same `config.collection_id` field works on [`POST /v1/image-search`](/api-reference/v1/image-search) and [`POST /experimental/find-products-in-image`](/api-reference/v1/find-products-in-image). A 404 means the id is missing or not owned by this API key. `/v1/similar` and `/v1/lookup` do not take a collection.

## List collections

List is paginated. Pass `user_id` to see one user's collections.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const page = await client.collections.list({ limit: 50 });

  for (const item of page.items) {
    console.log(item.collection_id, item.name);
  }

  if (page.next_page_token) {
    const next = await client.collections.list({
      limit: 50,
      page_token: page.next_page_token,
    });
  }
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  page = client.collections.list(limit=50)

  for item in page.items:
      print(item.collection_id, item.name)

  if page.next_page_token:
      next_page = client.collections.list(
          limit=50,
          page_token=page.next_page_token,
      )
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl "https://api.trychannel3.com/v1/collections?limit=50" \
    -H "x-api-key: $CHANNEL3_API_KEY"
  ```
</CodeGroup>

## Get a collection

Fetch one collection by id. The response includes name, description, `user_id`, and the full clause list.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const collection = await client.collections.retrieve(collectionId);

  console.log(collection.collection_id, collection.name);
  console.log(collection.clauses);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  collection = client.collections.retrieve(collection_id)

  print(collection.collection_id, collection.name)
  print(collection.clauses)
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl https://api.trychannel3.com/v1/collections/COLLECTION_ID \
    -H "x-api-key: $CHANNEL3_API_KEY"
  ```
</CodeGroup>

A 404 means the id is missing or not owned by this API key.

## Update a collection

PATCH replaces clauses in place by `clause_id`, removes by id, and/or appends new clauses.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const updated = await client.collections.update(collection.collection_id, {
    add_clauses: [{ brand_ids: ["brand_adidas_abc"] }],
  });
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  updated = client.collections.update(
      collection.collection_id,
      add_clauses=[{"brand_ids": ["brand_adidas_abc"]}],
  )
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X PATCH https://api.trychannel3.com/v1/collections/COLLECTION_ID \
    -H "x-api-key: $CHANNEL3_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "add_clauses": [{ "brand_ids": ["brand_adidas_abc"] }]
    }'
  ```
</CodeGroup>

<Cards>
  <Card title="Search" icon="magnifying-glass" href="/guides/search" arrow="true">
    Filters on a collection-scoped search further narrow results.
  </Card>

  <Card title="Conversations" icon="comments" href="/conversations" arrow="true">
    Bind a shopping chat to a collection.
  </Card>
</Cards>
