Skip to main content

Live Example

Overview

Use product discovery to power search bars, product detail pages, and catalog browsers across any merchant on the internet. Both products.search and products.details are async jobs - they return a refId, and results arrive once the background work completes. See Polling or Webhooks for how to handle the async pattern.

Prerequisites

import HenrySDK from '@henrylabs/sdk';

const henry = new HenrySDK({
	apiKey: process.env.HENRY_API_KEY!,
});

Search the catalog

1

Kick off a product search

Call products.search with a text query and optional filters. Returns immediately with a refId.
const search = await henry.products.search({
  query: 'Nike Air Max',
  // optional filters:
  merchant: 'nike.com',   // scope to a specific merchant
  limit: 20,              // 1–100, default 20
  sortBy: 'lowToHigh',    // or 'highToLow'
  minPrice: 50,
  maxPrice: 300,
  country: 'US',
});

console.log(search.refId, search.status);
// → "prs-ref_3fa8..." "pending"
2

Poll for results

Use products.pollSearch to check status until it’s "complete" or "failed". See Polling for the reusable helper and strategies.
const result = await henry.products.pollSearch({ refId: search.refId });
// result.status: "pending" | "processing" | "complete" | "failed"
3

Read the results

const { products, pagination } = result.result!;

for (const product of products) {
  console.log({
    name: product.name,
    price: `${product.price.amount} ${product.price.currency}`,
    merchant: product.merchant,
    link: product.link,       // use this as the cart item `link`
    inStock: product.availability?.available,
  });
}

// Paginate with the cursor
if (pagination.nextCursor) {
  const nextPage = await henry.products.search({
    query: 'Nike Air Max',
    cursor: Number(pagination.nextCursor),
  });
}

Fetch product details

If you need more granular product information, such as the availability of all variants, call products.details with the link from search for the full enriched payload.
1

Request product details

const detailJob = await henry.products.details({
  link: 'https://www.nike.com/t/air-max-270-shoes/AH8050-002',
  variant: { size: '10', color: 'Black' }, // optional pre-select a variant
  country: 'US', // optional default country
});

console.log(detailJob.refId, detailJob.status);
// → "prd-ref_3fa8..." "pending"
2

Poll for results

Use products.pollDetails to check status. See Polling for the reusable helper.
const detail = await henry.products.pollDetails({ refId: detailJob.refId });
// detail.status: "pending" | "processing" | "complete" | "failed"
3

Read the enriched product

const product = detail.result;

console.log({
  name: product?.name,
  price: product?.price,
  variants: product?.variants?.map(v => v.name),
  featuredImage: product?.images?.find(i => i.isFeatured)?.url,
});
Henry caches product details internally. If details for a link are already fresh, pollDetails will return "complete" on the very first call.

Search filters reference

ParameterTypeDescription
querystringRequired. Full-text search term
merchantstringMerchant name or host to scope the search (e.g. "nike.com")
limitnumberResults per page - 1 to 100, default 20
cursornumberPagination cursor from a previous response
sortBy"lowToHigh" | "highToLow"Sort by price
minPricenumberMinimum price filter
maxPricenumberMaximum price filter
countrystringISO country code for regional results (e.g. "US", "JP")

Error handling

ErrorCauseResolution
401 UnauthorizedInvalid API keyCheck HENRY_API_KEY
400 Bad RequestMissing query or invalid filter valuesValidate input before calling
status: "failed"Job error - check error fieldLog and retry

Next steps

Universal Cart

Use the product link to add items to a cart

Merchants

Browse supported merchants beforehand