> ## 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 catalog you curate yourself — brands, websites, categories, and specific products you pick. Create it once, then search, browse, and chat inside it by passing `config.collection_id`.

Creating and managing collections is **free**.

## What's in a collection

Each collection is made of one or more **clauses**. Inside a clause, fill in any of:

* **Any of these brands** (`brand_ids`)
* **Any of these websites** (`website_ids`)
* **Any of these categories** (`category_ids`)
* **Any of these products** (`product_ids`)

Let's walk through an example. You want Nike running shoes. That's one clause: Nike under brands, running shoes under categories.

<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"],
      },
    ],
  });
  ```

  ```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"],
          }
      ],
  )
  ```

  ```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>

Search inside that collection and you'll only get Nike products in running shoes — not all Nike, and not running shoes from other brands.

<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 },
  });
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  results = client.products.search(
      query="trail runners",
      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>

Want REI too? Adding a clause and adding to a clause give different results.

<Columns cols={2}>
  <Card title="Add a clause" icon="plus">
    Nike running shoes **or** anything from REI.

    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    add_clauses: [
      { website_ids: ["rei.com"] },
    ]
    ```
  </Card>

  <Card title="Add to the clause" icon="pen">
    Only Nike running shoes, and only from REI.

    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    replace_clauses: [{
      clause_id,
      brand_ids: [nikeId],
      category_ids: ["running-shoes"],
      website_ids: ["rei.com"],
    }]
    ```
  </Card>
</Columns>

Filters on a later search can only **narrow** what's already in the collection — they can't widen it. In the Nike running shoes collection:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Narrows: Nike running shoes under $150
await client.products.search({
  query: "trail runners",
  filters: { price: { max_price: 150 } },
  config: { collection_id: collection.collection_id },
});

// Zero results: this asks for Nike (the collection) AND Adidas (the filter)
await client.products.search({
  query: "trail runners",
  filters: { brand_ids: [adidasId] },
  config: { collection_id: collection.collection_id },
});
```

<Note>
  A collection can have up to 100 clauses, 100 IDs in each list per clause, and
  500 `product_ids` in total.
</Note>

For websites, you can pass a merchant ID or a domain like `nike.com`.

You can create an empty collection (`clauses: []`) and add clauses later.

Optional `user_id` ties the collection to one of your users. If a later search uses this collection and you don't send `x-user-id`, Channel3 attributes clicks to that user.

## Search, browse, image search, and similar

Pass the ID on `config.collection_id`.

<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), [`POST /v1/similar`](/api-reference/v1/similar-products), and [`POST /experimental/find-products-in-image`](/api-reference/v1/find-products-in-image). A 404 means that ID doesn't exist. `/v1/lookup` doesn't 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 every clause.

<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 that ID doesn't exist.

## Update a collection

PATCH can replace a clause in place by `clause_id`, remove one, or add another clause.

<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 search can only narrow what the collection returns.
  </Card>

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