Skip to main content
Every product in Channel3 has a category, and every category has a set of structured attributes — machine-extracted features like material, connectivity, power source, and thousands of others. Combining category detail lookup with the attributes search filter lets you express queries that plain text search can’t — for example, finding sofas that have USB charging ports.

The two-step pattern

  1. Discover the category and its attributes — look up the category detail to see which attribute keys are defined and what values they accept.
  2. Search with an attribute filter — pass those key/value pairs to /v1/search to get precisely matched products.

Step 1 — Get a category slug

You need a category slug (for example sofas) before you can inspect its attributes. Either find one by text, or grab it from a product you already have.

Option A — Search for the category

Use the category search endpoint to look up by free text:
import Channel3 from "@channel3/sdk";

const client = new Channel3();

const categoryResults = await client.categories.search({ query: "sofas" });

// Pick the best-matching category
const category = categoryResults.categories[0];
console.log(category.slug); // e.g. "sofas"
console.log(category.title); // "Sofas"

Option B — Grab the category from an existing product

If you already have a representative product — from a search result, lookup, or your own catalog — read its category.slug instead of searching:
const product = await client.products.retrieve("2yh8WH5");
const slug = product.category.slug; // e.g. "sofas"

Step 2 — Retrieve category detail to see its attributes

Call the category detail endpoint with the slug to get the full list of attributes for that category. Each attribute has a handle (the key you’ll pass to the filter) and a list of known values.
const categoryDetail = await client.categories.retrieve("sofas");

// Print all attributes and their example values
for (const attr of categoryDetail.attributes) {
  console.log(`${attr.handle}: ${attr.values.slice(0, 5).join(", ")}`);
}
// connectivity: USB, Bluetooth, None
// material:     Leather, Velvet, Linen, Microfiber, ...
// seating_capacity: 2, 3, 4, Sectional
// style:        Mid-Century Modern, Contemporary, ...
// color:        Beige, Gray, Navy, ...
The attributes available vary by category. Always retrieve category detail first — don’t guess attribute handles.

Step 3 — Search with the attribute filter

Now you have the attribute key and its accepted values. Pass them to POST /v1/search via the attributes filter. The attributes filter takes a map of handle → [values].
const results = await client.products.search({
  query: "sofa",
  filters: {
    category: "sofas",
    attributes: {
      connectivity: ["USB"],
    },
  },
  limit: 20,
});

console.log(`Found ${results.products.length} sofas with USB charging`);
results.products.forEach((p) => {
  console.log(p.title, p.offers[0]?.price);
});

Full end-to-end example

Here’s the complete three-step flow in a single function — discover the category, inspect its attributes, then search:
import Channel3 from "@channel3/sdk";

const client = new Channel3();

async function findSofasWithUSB() {
  // 1. Find the category
  const { categories } = await client.categories.search({ query: "sofas" });
  const slug = categories[0].slug; // "sofas"

  // 2. Inspect its attributes
  const detail = await client.categories.retrieve(slug);
  const connectivityAttr = detail.attributes.find(
    (a) => a.handle === "connectivity",
  );

  if (!connectivityAttr?.values.includes("USB")) {
    console.warn("USB not listed as a connectivity value for this category");
  }

  // 3. Search with the attribute filter
  const results = await client.products.search({
    query: "sofa",
    filters: {
      category: slug,
      attributes: { connectivity: ["USB"] },
    },
    limit: 20,
  });

  return results.products;
}

findSofasWithUSB().then((products) => {
  console.log(`Found ${products.length} sofas with USB ports:`);
  products.forEach((p) => console.log(" -", p.title));
});

Combining multiple attributes

Pass multiple keys to narrow further. Values within a key are OR’d; keys are AND’d — so the example below finds sofas that are (USB OR Bluetooth) connectivity and Velvet material:
const results = await client.products.search({
  query: "sofa",
  filters: {
    category: "sofas",
    attributes: {
      connectivity: ["USB", "Bluetooth"],
      material: ["Velvet"],
    },
  },
});

Reading structured_attributes on a product

Products returned from /v1/products/{id} and /v1/lookup include a structured_attributes field — a map of attribute handles to their extracted values for that specific product. Use it to display feature chips on a PDP, or to understand what attributes a specific product carries.
TypeScript
const product = await client.products.retrieve("2yh8WH5");

const attrs = product.structured_attributes;
// {
//   connectivity: "USB",
//   material:     "Velvet",
//   color:        "Navy Blue",
//   seating_capacity: "3",
// }

console.log(`Connectivity: ${attrs.connectivity}`);
console.log(`Material: ${attrs.material}`);
structured_attributes is populated on product detail (GET /v1/products/{id} and POST /v1/lookup). It is not returned on search results.