# Coolblue API — live product, price, stock and specification data scraper for coolblue.nl, coolblue.be and coolblue.de: keyword search with the retailer's own result count, category browsing with the printed delivery promise, the full manufacturer spec table, review scores and per-store pickup availability — no API key, no login

> Search Coolblue by keyword: product id, name, price in euro, the delivery promise the site prints beside the product, the review score and the key specs. When the keyword is a whole category Coolblue answers with that category instead of a result list — this endpoint follows that and tells you so in `resolved_as`, so a search for 'headphones' returns headphones rather than an error. `total` is Coolblue's own match count and is present on keyword result sets.
> ReefAPI engine `coolblue` · 6 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/coolblue/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). Send the key as `Authorization: Bearer <key>`, or put it in the URL (`?key=<key>`) when the client has no header field, as ChatGPT does.

## Endpoints

### POST https://api.reefapi.com/coolblue/v1/search — 3 credits
Search Coolblue by keyword: product id, name, price in euro, the delivery promise the site prints beside the product, the review score and the key specs. When the keyword is a whole category Coolblue answers with that category instead of a result list — this endpoint follows that and tells you so in `resolved_as`, so a search for 'headphones' returns headphones rather than an error. `total` is Coolblue's own match count and is present on keyword result sets.

**Parameters:**
- `query` (string, required) — What to search for, in English or Dutch. A product number (979101) or a manufacturer code (EP2-61329) also resolves to the single matching product.
- `market` (enum, optional, default "nl") — Which storefront to ask. Prices and stock genuinely differ between them (measured: 5 of 7 shared products had a different price on nl vs be) and each market lists products the others do not. [one of: nl, be, de]
- `filters` (array, optional) — Facet segments in 'key:value' form, for example 'merk:apple'. One value per key (the source answers a multi-value '+' form with 404). Call the 'filters' action to list what a category accepts, with the result count behind each value.
- `sort` (enum, optional, default "relevance") — Result order. All five were measured to genuinely reorder the grid. An unknown value is rejected rather than passed on, because the source accepts any string and silently ignores what it does not know. [one of: relevance, lowest-price, highest-price, most-sold, highest-rated]
- `page` (integer, optional, default 1) — Page of results. Coolblue stops a keyword result set at page 20: page 21 returns HTTP 404, so at most 480 products of a larger set are reachable and `results_reachable` reports it. Narrow with `filters` to reach the rest.

**Returns:** results[]{product_id, name, url, brand, price_eur, price_excl_vat_eur, price_display, rating_out_of_10, review_count, delivery_promise, delivery_state, availability, in_stock, second_chance_price_eur, highlights[], colour_variants[], image}, total, page, page_size, pages_available, results_reachable, resolved_as{kind, category}, market, dropped_tiles

**Example request body:**
```json
{
  "query": "usb c cable"
}
```

### POST https://api.reefapi.com/coolblue/v1/browse — 3 credits
Walk one of Coolblue's 403 categories — the catalogue view, and the richer of the two surfaces. Rows carry the typed delivery promise, the price with and without VAT, the review average, how many stores hold the item, the refurbished (Second Chance) price when there is one, and the colour variants. Use `categories` for the slugs and `filters` for the narrowing options.

**Parameters:**
- `category` (string, required) — A Coolblue category slug such as 'headphones', 'washing-machines' or 'laptops', or a category URL. The `categories` action lists all 403 of them.
- `market` (enum, optional, default "nl") — Which storefront to ask. Prices and stock genuinely differ between them (measured: 5 of 7 shared products had a different price on nl vs be) and each market lists products the others do not. [one of: nl, be, de]
- `filters` (array, optional) — Facet segments in 'key:value' form, for example 'merk:apple'. One value per key (the source answers a multi-value '+' form with 404). Call the 'filters' action to list what a category accepts, with the result count behind each value.
- `sort` (enum, optional, default "relevance") — Result order. All five were measured to genuinely reorder the grid. An unknown value is rejected rather than passed on, because the source accepts any string and silently ignores what it does not know. [one of: relevance, lowest-price, highest-price, most-sold, highest-rated]
- `page` (integer, optional, default 1) — Page of 22 results. A category publishes its own `total_pages`; asking past it returns NOT_FOUND.

**Returns:** results[] (same row shape as search), page, page_size, total_pages, category, filters, market

**Example request body:**
```json
{
  "category": "headphones"
}
```

### POST https://api.reefapi.com/coolblue/v1/product/detail — 3 credits
One full product record by id or Coolblue URL: price including and excluding VAT, stock state, how many of Coolblue's stores hold it and how many can hand it over, the complete manufacturer specification table, the review average with its 1-5 star distribution, Coolblue's own pros and cons, and every gallery image. The answer also carries `source_check`, which compares the price against the schema.org copy the same page publishes so you can see the two agree.

**Parameters:**
- `product_id` (string, required) — The Coolblue product number (979101) or any Coolblue product URL. The id alone is enough — no slug needed.
- `market` (enum, optional, default "nl") — Which storefront to ask. Prices and stock genuinely differ between them (measured: 5 of 7 shared products had a different price on nl vs be) and each market lists products the others do not. [one of: nl, be, de]
- `include_specs` (boolean, optional, default true) — Include the specification table. Turn it off for a smaller answer when you only want price and stock; it costs the same, because it is the same page.

**Returns:** product{product_id, name, brand, url, price_eur, price_excl_vat_eur, list_price_eur, availability, in_stock, stores_listed, stores_with_stock, stores_available_for_pickup, rating_out_of_10, review_count, review_distribution_stars[], pros[], cons[], description, image, images[], specifications[]{group,name,value}, specification_groups[], specification_count, source_check{...}}

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

### POST https://api.reefapi.com/coolblue/v1/products/batch — 20 credits
Up to 10 products in ONE call — the shape a price tracker runs on. Each row carries price, stock, rating and the id, and any id this market does not sell is named in `missing` instead of being silently dropped. Specifications are off by default here to keep the answer readable.

**Parameters:**
- `product_ids` (array, required) — Between 1 and 10 Coolblue product numbers or product URLs.
- `market` (enum, optional, default "nl") — Which storefront to ask. Prices and stock genuinely differ between them (measured: 5 of 7 shared products had a different price on nl vs be) and each market lists products the others do not. [one of: nl, be, de]
- `include_specs` (boolean, optional, default false) — Include each product's specification table. Off by default because ten full spec tables is a large answer.

**Returns:** products[]{same shape as product/detail}, requested, returned, missing[], market

**Example request body:**
```json
{
  "product_ids": [
    "979101",
    "947006",
    "923419"
  ]
}
```

### POST https://api.reefapi.com/coolblue/v1/filters — 2 credits
The filter vocabulary a category actually accepts: every facet key, its English title, and the values behind it — each with the exact `key:value` segment to pass back into `browse` or `search` AND the number of products behind it, so you can see a filter bite before spending a call on it. This exists because the facet keys are Dutch even on the English storefront (the brand filter is `merk`), so they cannot be guessed.

**Parameters:**
- `category` (string, required) — The category whose filters to list, for example 'headphones'.
- `filters` (array, optional) — Show the filters still available after these segments are applied, with their updated counts — this is how you discover the narrowing options inside a selection.
- `market` (enum, optional, default "nl") — Which storefront to ask. Prices and stock genuinely differ between them (measured: 5 of 7 shared products had a different price on nl vs be) and each market lists products the others do not. [one of: nl, be, de]

**Returns:** filters[]{key, title, type, value_count, values[]{value, segment, label, result_count, selected}}, filter_count, category, market

**Example request body:**
```json
{
  "category": "headphones"
}
```

### POST https://api.reefapi.com/coolblue/v1/categories — 1 credit
Every Coolblue category, read from the sitemap it publishes for crawlers: the slug you pass to `browse` and `filters`, and its path on the site. One small request, and the slugs were verified against the live grid rather than assumed.

**Parameters:**
- `market` (enum, optional, default "nl") — Which storefront to ask. Prices and stock genuinely differ between them (measured: 5 of 7 shared products had a different price on nl vs be) and each market lists products the others do not. [one of: nl, be, de]
- `contains` (string, optional) — Only return categories whose slug contains this text.

**Returns:** categories[]{category, url_path}, count, market

**Example request body:**
```json
{
  "contains": "washing"
}
```

## At scale
- **Volume:** 5M+ requests a day, measured at 60 requests a second across the fleet with no
  central bottleneck. Per-key limits are raised for high-volume accounts; volume pricing on request.
- **Missing a source:** tell us a site we do not cover and it becomes an engine. A customer asked
  for bestprice.gr on 21 Sep 2026 and it was in the catalog on 22 Sep.
- **Support:** 2 minute median time from a question in the live chat to the first answer. Setup
  help included, no support tier to buy.
- **One key, one credit pool** across every API. No per-site plans, no separate subscriptions.

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