# iHerb — supplements & natural health, priced per country

> Keyword search on one country's storefront. Returns the storefront's own result total plus the filtered total so a filter's effect is visible.
> ReefAPI engine `iherb` · 8 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/iherb/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed calls are free except verified SHEIN NOT_FOUND on product/detail and price (4 credits).
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http, `Authorization: Bearer <key>`) and your assistant can call these actions directly.

## Endpoints

### POST /iherb/v1/search — 3 credits
Keyword search on one country's storefront. Returns the storefront's own result total plus the filtered total so a filter's effect is visible.

**Parameters:**
- `keyword` (string, required) — What to search for.
- `country` (enum, optional, default "US") — Which national storefront to price against. Prices, availability and even the number of matching products differ per storefront. [one of: AE, AU, BR, CA, DE, ES, FR, GB, HK, IL, IN, IT, JP, KR, MX, MY, NL, NZ, PH, PL, SA, SE, SG, TH, TR, TW, UA, US, VN, ZA]
- `page` (integer, optional, default 1) — 1-based page.
- `page_size` (integer, optional, default 24) — Products per page. iHerb serves at most 48.
- `sort` (enum, optional) — Result order. NOTE: iHerb's sorted result set is SMALLER than its unsorted one (measured 14807 -> 10559 for the same keyword), so sorting changes which products you see, not just their order. [one of: featured, relevance, best_sellers, top_rated, most_rated, price_asc, price_desc, newest, heaviest, lightest, highest_discount]
- `rating_band` (integer, optional) — iHerb's star BAND, 1-5. This is a band, NOT a minimum: measured on one storefront, band 5 returns products rated about 4.8 and up, band 4 about 3.8-4.7, band 3 about 2.8-3.7. Asking for 3 therefore EXCLUDES 4- and 5-star products. The `filters` action prints how many products sit in each band.
- `brand_codes` (array, optional) — iHerb brand codes, e.g. NOW. Discover them with the `filters` action.
- `category_ids` (array, optional) — iHerb category ids; see the `filters` action.
- `price_ranges` (array, optional) — iHerb price-band ids (they are bands, not amounts; the band's boundaries are in that storefront's own currency).
- `health_topics` (array, optional) — Health-topic ids, e.g. Immune Support; see the `filters` action.
- `attribute_ids` (array, optional) — Attribute value ids — diet/certification/form/age; see `filters`.
- `programs` (array, optional) — Programme ids, e.g. iTested.
- `in_stock_only` (boolean, optional, default false) — Drop out-of-stock products.

**Returns:** { total, returned, products[], country, currency, sort_changes_population } — each product carries price_amount + currency + the storefront it came from.

**Example request body:**
```json
{
  "keyword": "vitamin c",
  "country": "US"
}
```

### POST /iherb/v1/category — 2 credits
Browse one catalogue category on one country's storefront.

**Parameters:**
- `slug` (string, required) — Category slug from the URL, e.g. vitamin-c. List them with `categories`.
- `country` (enum, optional, default "US") — Which national storefront to price against. [one of: AE, AU, BR, CA, DE, ES, FR, GB, HK, IL, IN, IT, JP, KR, MX, MY, NL, NZ, PH, PL, SA, SE, SG, TH, TR, TW, UA, US, VN, ZA]
- `page` (integer, optional, default 1) — 1-based page.
- `page_size` (integer, optional, default 24) — Max 48.
- `sort` (enum, optional) — Result order; see the note on `search.sort` — sorting shrinks the set. [one of: featured, relevance, best_sellers, top_rated, most_rated, price_asc, price_desc, newest, heaviest, lightest, highest_discount]
- `rating_band` (integer, optional) — iHerb's star BAND, 1-5. This is a band, NOT a minimum: measured on one storefront, band 5 returns products rated about 4.8 and up, band 4 about 3.8-4.7, band 3 about 2.8-3.7. Asking for 3 therefore EXCLUDES 4- and 5-star products. The `filters` action prints how many products sit in each band.
- `brand_codes` (array, optional) — iHerb brand codes.
- `category_ids` (array, optional) — Narrow to sub-category ids.
- `price_ranges` (array, optional) — Price-band ids.
- `health_topics` (array, optional) — Health-topic ids.
- `attribute_ids` (array, optional) — Attribute value ids.
- `programs` (array, optional) — Programme ids.
- `in_stock_only` (boolean, optional, default false) — Drop out-of-stock products.

**Returns:** { total, returned, products[], category, breadcrumbs, country, currency }

### POST /iherb/v1/detail — 1 credit
One product in full on one country's storefront: price, stock count, supplement facts, ingredients, pack size, rating, shipping weight.

**Parameters:**
- `product_id` (integer, required) — iHerb numeric product id — the last path segment of a product URL.
- `country` (enum, optional, default "US") — Which national storefront to price against. [one of: AE, AU, BR, CA, DE, ES, FR, GB, HK, IL, IN, IT, JP, KR, MX, MY, NL, NZ, PH, PL, SA, SE, SG, TH, TR, TW, UA, US, VN, ZA]

**Returns:** A product record. `supplement_facts` is a row list parsed out of iHerb's own table; `ingredients`/`warnings`/`suggested_use` are plain text.

**Example request body:**
```json
{
  "product_id": 1135,
  "country": "US"
}
```

### POST /iherb/v1/batch_detail — 3 credits
Up to 20 products in one call, on one storefront. iHerb has no batch route of its own, so this fans out — but it is priced below the equivalent single calls.

**Parameters:**
- `product_ids` (array, required) — Up to 20 iHerb product ids.
- `country` (enum, optional, default "US") — Which national storefront to price against. [one of: AE, AU, BR, CA, DE, ES, FR, GB, HK, IL, IN, IT, JP, KR, MX, MY, NL, NZ, PH, PL, SA, SE, SG, TH, TR, TW, UA, US, VN, ZA]

**Returns:** { requested, returned, products[], not_found[] }

### POST /iherb/v1/price_by_country — 3 credits
The same product priced across several national storefronts in one call — price, currency, availability and shipping restrictions side by side. This is what iHerb being a cross-border retailer actually means in data.

**Parameters:**
- `product_id` (integer, required) — iHerb numeric product id.
- `countries` (array, optional) — Storefronts to compare, max 12. Defaults to US, GB, DE, JP, KR.

**Returns:** { product_id, name, brand, markets[] } — one row per storefront with price_amount, currency, in_stock and the local display price.

**Example request body:**
```json
{
  "product_id": 1135,
  "countries": [
    "US",
    "JP"
  ]
}
```

### POST /iherb/v1/reviews — 3 credits
Customer reviews for a product, with the per-star breakdown and iHerb's own summary of them. Public — no account is involved.

**Parameters:**
- `product_id` (integer, required) — iHerb numeric product id.
- `country` (enum, optional, default "US") — Storefront to read reviews from — it decides the language they are shown in and which reviews are surfaced. [one of: AE, AU, BR, CA, DE, ES, FR, GB, HK, IL, IN, IT, JP, KR, MX, MY, NL, NZ, PH, PL, SA, SE, SG, TH, TR, TW, UA, US, VN, ZA]
- `page` (integer, optional, default 1) — 1-based page, 10 reviews per page.

**Returns:** { rating, rating_count, star_counts, summary, reviews[] } — 10 reviews per page with text, title, star rating, date and verified-purchase flag.

**Example request body:**
```json
{
  "product_id": 1135
}
```

### POST /iherb/v1/categories — 1 credit
Every browsable catalogue category iHerb publishes (~1 480).

**Parameters:**
- `search` (string, optional) — Keep only categories whose slug contains this text.

**Returns:** { total, categories[] } with slug + url, ready for the `category` action.

### POST /iherb/v1/filters — 2 credits
The filter vocabulary for a keyword or category on one storefront — brand codes, category ids, attribute ids and how many products sit behind each, so the opaque ids the other actions take are discoverable.

**Parameters:**
- `keyword` (string, optional) — Filters for this search.
- `slug` (string, optional) — Filters for this category instead.
- `country` (enum, optional, default "US") — Which storefront's vocabulary. [one of: AE, AU, BR, CA, DE, ES, FR, GB, HK, IL, IN, IT, JP, KR, MX, MY, NL, NZ, PH, PL, SA, SE, SG, TH, TR, TW, UA, US, VN, ZA]

**Returns:** { total, filters[] } — each with key, label and options[{label,value,count}].

## More
- Try it live, no code: https://reefapi.com/playground?engine=iherb
- Human docs page: https://reefapi.com/docs/iherb
- Overview page: https://reefapi.com/iherb-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
