Looking for the overview — what this API returns, what it costs, and a call you can run without a key? See the bol.com API page →
E-commerce & Marketplaces

bol.com API & Scraper

The bol.com API returns the leading online retailer of the Netherlands and Belgium as clean JSON, across four actions - search, product/detail, product/offers and category - and three storefronts: Dutch (nl), Belgian Dutch (be) and Belgian French (be-fr).

4 actionsLive JSON1,000 free credits$0.67–$1.50 / 1,000 creditsMCP-ready
Get a free keyOpen in playground

🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.

product/offers is the cheap and interesting one: bol is a marketplace and publishes its whole competing-offer table, so one call returns every seller for a product with that seller's price, condition, offer type, shipping cost, delivery promise and bol's own 1-to-10 seller rating - and it costs about a sixth of what a product page costs upstream. Listing rows carry the product id and URL, title, brand, the current price and bol's 90-day reference price, the discount, the seller behind the buy-box, the delivery promise, the rating and the category path; a 199-product grid across 7 bol departments filled every one of those on every row. product/detail adds the EAN and MPN, the full image gallery, the spec groups, the description and the sibling products that differ only by colour or size. Prices are EUR. No bol account, no browser - one ReefAPI key and the standard envelope.

Reference

Seven bol behaviours worth knowing before you build against it

All measured on 2026-09-06 across 135 live calls, three storefronts and 199 products in 7 departments.

BehaviourMeasuredWhat to do
NL and BE are different prices, not different languagesproduct 9200000032872507 was 15.00 EUR on the Dutch storefront and 13.05 EUR on both Belgian storefronts, in the same minutetreat market as a real parameter. If you are price-monitoring the Benelux, you need both
The competing-seller table is far cheaper than the product pageproduct/offers has a median of 1,224 ms against 1,550 ms for product/detail, and moves 45-48 KB against 288 KBif what you want is who sells it and for how much, call product/offers directly rather than the product page
The numeric id is the key; the slug is decorationthe same product resolves under any slug, and a category URL carrying the koptelefoons slug with id 4770 serves Laptops - because 4770 IS Laptopspass the bare id. The category action echoes bol's own name for what it resolved, so a wrong id is visible instead of silent
Search stops at page 10; category browse does notsearch page 11 returns 0 rows and a total of 0. The Laptops category reported 114 pagesthe page limit is published on the parameter, so page 11 is rejected rather than charged for. Browse a category when you need depth
total_results is sometimes an estimate and says soone query's total moved between 10,006 and 60,468 on identical calls; large categories clamp at exactly 300,000read total_results_is_estimate before you put the number in a report
EAN is on the product, not on the listing row0 of 199 listing rows carried an EAN; product/detail returned a real one on 7 of 7 products checked, one per departmentbol ships a summary spec block on a card and the full spec groups only on the product, and EAN lives in a group
Two sort values actually biteprice ascending and price descending were both proven on the ORGANIC rows only, because sponsored tiles are injected out of order. Everything else returned a byte-identical default orderonly the two that were proven are published; the rest are rejected rather than accepted and ignored

bol translates spec VALUES per storefront, not only labels: the same product's Model reads "Ace" on the Dutch storefront and "As" on the Belgian French one. The engine keys off bol's stable English machine keys (EAN, Mpn, Model, Colour) but returns whatever value that storefront publishes - inventing a canonical value would be fabricating one.

Live example

Real request and response JSON

Captured from the indexed primary action, search, on .

Captured request
{
  "method": "POST",
  "url": "https://api.reefapi.com/bol/v1/search",
  "headers": {
    "x-api-key": "$REEF_KEY",
    "content-type": "application/json"
  },
  "body": {
    "query": "koptelefoon"
  }
}
Captured response
{
  "ok": true,
  "meta": {
    "api": "bol",
    "endpoint": "search",
    "mode": "live",
    "latency_ms": 2460,
    "record_count": 29,
    "bytes": 667684,
    "cache_hit": false,
    "page": 1,
    "market": "nl"
  },
  "data": {
    "products": [
      {
        "product_id": "[redacted-phone]",
        "title": "Sonos Ace - Draadloze hoofdtelefoon - Noise Cancelling - Dolby Atmos - TV Audio Swap - Zwart",
        "url": "https://www.bol.com/nl/nl/p/sonos-ace-zwart/[redacted-phone]/",
        "brand": {
          "id": "4253982",
          "name": "Sonos",
          "url": "https://www.bol.com/nl/nl/pb/sonos/4253982/"
        },
        "price": 307,
        "currency": "EUR",
        "reference_price": 342,
        "discount_percent": 10,
        "condition": "new",
        "seller": {
          "id": "0",
          "name": "bol",
          "is_bol": true,
          "rating": null,
          "rating_count": null,
          "top_seller": null
        },
        "delivery": {
          "description": "Op voorraad. Voor 23:59 uur besteld, morgen in huis",
          "arrives_by": "[redacted-phone]",
          "release_date": null,
          "shipping_cost": null,
          "within_48h": true
        },
        "low_stock": false,
        "promotions": [
          "deal"
        ],
        "offer_id": "4c86098a-554a-45f3-875f-54922835c040",
        "rating": 4.8,
        "review_count": 6,
        "image": "https://media.s-bol.com/43p9oWPzz557/rkV8946/550x838.jpg",
        "category": "Koptelefoons",
        "category_path": [
          "Elektronica",
          "Audio & Hifi",
          "Audio voor jou"
        ],
        "ean": null,
        "highlights": [
          "Over-ear",
          "Draadloos",
          "Noise cancelling"
        ],
        "pack_quantity": null,
        "energy_label": null,
        "sponsored": true,
        "offers_url": "https://www.bol.com/nl/nl/prijsoverzicht/sonos-ace-zwart/[redacted-phone]/?filter=new&sort=price&sortOrder=asc"
      },
      {
        "product_id": "[redacted-phone]",
        "title": "PowerLocus MoonFly Bluetooth Koptelefoon – Over-Ear Active Noise Cancelling Koptelefoon – 70 uur batterijduur – Microfoon – incl. Premium Case - Zwart",
        "url": "https://www.bol.com/nl/nl/p/powerlocus-moonfly-bluetooth-koptelefoon-over-ear-active-noise-cancelling-koptelefoon-70-uur-batterijduur-microfoon-incl-premium-case-zwart/[redacted-phone]/",
        "brand": {
          "id": "16984845",
          "name": "PowerLocus",
          "url": "https://www.bol.com/nl/nl/b/powerlocus/16984845/"
        },
        "price": 41.99,
        "currency": "EUR",
        "reference_price": 49.99,
        "discount_percent": 16,
        "condition": "new",
        "seller": {
          "id": "1320796",
          "name": "Mition",
          "is_bol": false,
          "rating": null,
          "rating_count": null,
          "top_seller": null
        },
        "delivery": {
          "description": "Op voorraad. Voor 23:59 uur besteld, morgen in huis",
          "arrives_by": "[redacted-phone]",
          "release_date": null,
          "shipping_cost": null,
          "within_48h": true
        },
        "low_stock": false,
        "promotions": [
          "deal"
        ],
        "offer_id": "a9d50d66-edd4-cf6f-e[redacted-phone]a535f",
        "rating": 4.3,
        "review_count": 304,
        "image": "https://media.s-bol.com/gqg3BrMQGgWl/ADxKqwB/550x587.jpg",
        "category": "Koptelefoons",
        "category_path": [
          "Elektronica",
          "Audio & Hifi",
          "Audio voor jou"
        ],
        "ean": null,
        "highlights": [
          "Over-ear",
          "Draadloos",
          "Noise cancelling"
        ],
        "pack_quantity": null,
        "energy_label": null,
        "sponsored": true,
        "offers_url": "https://www.bol.com/nl/nl/prijsoverzicht/powerlocus-moonfly-bluetooth-koptelefoon-over-ear-active-noise-cancelling-koptelefoon-70-uur-batterijduur-microfoon-incl-premium-case-zwart/[redacted-phone]/?filter=new&sort=price&sortOrder=asc"
      },
      {
        "product_id": "[redacted-phone]",
        "title": "Sony MDR-ZX110 - On-ear koptelefoon - Zwart",
        "url": "https://www.bol.com/nl/nl/p/sony-mdr-zx110-on-ear-koptelefoon-zwart/[redacted-phone]/",
        "brand": {
          "id": "3123135",
          "name": "Sony",
          "url": "https://www.bol.com/nl/nl/pb/sony/3123135/"
        },
        "price": 15,
        "currency": "EUR",
        "reference_price": null,
        "discount_percent": null,
        "condition": "new",
        "seller": {
          "id": "0",
          "name": "bol",
          "is_bol": true,
          "rating": null,
          "rating_count": null,
          "top_seller": null
        },
        "delivery": {
          "description": "Op voorraad. Voor 23:59 uur besteld, morgen in huis",
          "arrives_by": "[redacted-phone]",
          "release_date": null,
          "shipping_cost": null,
          "within_48h": true
        },
        "low_stock": false,
        "promotions": null,
        "offer_id": "078ae9e4-dfa4-47db-a7ac-a2a18ed33611",
        "rating": 4.5,
        "review_count": 403,
        "image": "https://media.s-bol.com/qxxrK46A8Ko7/539x840.jpg",
        "category": "Koptelefoons",
        "category_path": [
          "Elektronica",
          "Audio & Hifi",
          "Audio voor jou"
        ],
        "ean": null,
        "highlights": [
          "On-ear",
          "Niet draadloos",
          "Geen microfoon"
        ],
        "pack_quantity": null,
        "energy_label": null,
        "sponsored": false,
        "offers_url": "https://www.bol.com/nl/nl/prijsoverzicht/sony-mdr-zx110-on-ear-koptelefoon-zwart/[redacted-phone]/?filter=new&sort=price&sortOrder=asc"
      }
    ],
    "count": 29,
    "page": 1,
    "total_results": 64330,
    "total_results_is_estimate": false,
    "total_pages": 10,
    "categories": [
      {
        "id": "3136",
        "name": "Elektronica",
        "url": "https://www.bol.com/nl/nl/s/?searchtext=koptelefoon&N=3136"
      },
      {
        "id": "33078",
        "name": "Koptelefoons",
        "url": "https://www.bol.com/nl/nl/s/?searchtext=koptelefoon&N=33078"
      },
      {
        "id": "14035",
        "name": "Wonen",
        "url": "https://www.bol.com/nl/nl/s/?searchtext=koptelefoon&N=14035"
      }
    ],
    "query": "koptelefoon"
  }
}
Actions

What the bol.com API does

ActionDescriptionConcrete use caseKey params
searchSearch bol.com by keyword, paginated. Every row carries the product id and url, title, brand, the current price and bol's own 90-day reference price, the discount, the seller behind the buy-box (bol itself or a marketplace partner), the delivery promise, the rating and review count, the category path, the EAN when bol publishes one, and whether the row is a paid placement. The response also returns the ids of the categories the results fall into, which is what `category` takes.Pricing teams call search to search bol.com by keyword, paginated.query, page, sort, market, max_rotations
product/detailFull bol.com product by id (or by its url): title, brand, EAN and MPN, the buy-box price with bol's 90-day reference price and the discount, the seller, the delivery promise, the full image gallery, the complete specification table, the description as plain text, the category breadcrumb, the average rating and review count, and how many competing offers exist. Review TEXT is not returned - bol serves it only to a signed-in session, and this endpoint never invents it.Marketplace operators call product/detail to get full bol.com product by id (or by its url).product_id, market, max_rotations
product/offersEvery seller offering one bol.com product, with that seller's price, condition, delivery promise, shipping cost and bol seller rating - bol is a marketplace and this is the competing-offer table behind the buy-box, on bol's own price-overview page. Cheap: about 45 KB per call against 290 KB for the product page.Catalog enrichment teams call product/offers to get every seller offering one bol.com product, with that seller's price, condition, delivery prom….product_id, market, max_rotations
categoryBrowse a bol.com category by its id, paginated - the same rich product row `search` returns, plus the category bol resolved and its breadcrumb. Category listings page far deeper than search does and their result total is exact rather than estimated.Retail analysts call category to get browse a bol.com category by its id, paginated - the same rich product row `search` returns,….category_id, page, sort, market, max_rotations
Code samples

Call search from your stack

curl -X POST https://api.reefapi.com/bol/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"query":"koptelefoon"}'
MCP one-liner
Ask your MCP-connected assistant: call reefapi.bol.search with {"query":"koptelefoon"}.
Use cases

Who uses this API and why

  • Benelux price monitors call product/offers for the whole competing-seller table at a sixth of the cost of a product page.
  • Marketplace sellers check where their own offer sits against every other seller on the same bol listing, with each seller's bol rating attached.
  • Cross-border pricing teams run nl, be and be-fr on the same product id to see the real price gap between the Dutch and Belgian storefronts.
  • Catalog teams call product/detail for the EAN, the MPN, the full spec groups and the sibling listings that differ only by colour or size.
FAQ

Questions developers ask before integrating

What does one product/offers call return?

One row per seller offering that product, plus a breakdown of how many offers are new, refurbished and second-hand. A measured call on the Anker Soundcore Space One returned 6 sellers between 84.00 and 92.71 EUR - Anker Direct, ASD, gsmpunt, Eufy Official, bol itself and IT Distributie - each with its price, condition, shipping cost, the date it arrives, whether that is within 48 hours, and its bol seller rating out of 10. Across a 7-product chain check the action returned 1, 1, 1, 1, 2, 3 and 6 offers, so multi-seller products are common but not universal.

Why does bol's own row have no seller rating?

Because bol is not one of its own marketplace partners, so it has no partner rating to publish. That row comes back with the rating and top-seller flag null and an explicit is_bol flag set, rather than being filled in with a flattering default. Every third-party seller does carry a rating - 8.7, 8.4 and 9.3 on the measured rows - on bol's 1-to-10 scale.

Is be a language switch or a different market?

A different market. The same product measured 15.00 EUR on the Dutch storefront and 13.05 EUR on both Belgian ones within the same minute, so prices genuinely differ. be and be-fr are the Dutch and French storefronts of Belgium - a French search returns French titles and French category names for the same product ids. Both Belgian storefronts and the Dutch one were verified on all four actions.

What is the reference price, and is it a list price?

It is not an RRP and it is not returned as one. bol defines it as the most-shown price of the last 90 days excluding promotions, and it is returned under that name, on roughly the 40% of rows that have one. The discount is computed against that, so a discount here means "cheaper than bol has typically been showing it", not "cheaper than the manufacturer's list price" - which bol does not publish anywhere in the payload.

How does bol model colours and sizes?

As separate products with their own ids, which is bol's own model rather than a variant matrix. product/detail returns those siblings in a related-products list along with the feature that distinguishes them - Kleur for colour, Maat for size - so you can walk to them, but there is no size grid to read and none is invented. This is worth knowing before you build a variant table: on bol the price and the seller can differ per colour, because each colour is its own listing.

Does bol publish stock levels or review text?

Neither, and both are null. What bol publishes instead of a stock count is a delivery promise ("in stock, order before 23:59 and it arrives tomorrow"), a latest-arrival date and a scarcity flag - there is no number anywhere in the payload. Review text sits behind an authenticated call that returns 403 without a session, so only the average rating and the review total are returned. Seller legal details - address, chamber-of-commerce number, phone - live on a separate bol page this engine does not read.

Why is brand empty on some book rows?

Because a book has no brand on bol - it has an author, which bol publishes as a specification rather than as a brand. Measured: brand was filled on 5 of 30 rows in the Boeken department and on 28 of 28 in Films, where the field itself is clearly working ("Warner Home Video"). Ratings are similar: 6 of 28 Films rows had one, because most of those titles have no reviews yet. The gaps are bol's, and they come back null.

How fast and how reliable is it?

135 live calls across three separate runs came back 135 successful, with a median around 1.8 to 2.2 seconds. Per action on the shipped build: product/offers 1,224 ms, product/detail 1,550 ms, search 2,219 ms, category 2,694 ms. There is a real tail - one search in 135 took 17.2 seconds on a single slow exit - and an occasional block that is typed as retryable so the gateway re-leases and tries again. No storefront is meaningfully slower than another.

What is the bol.com API?

bol.com API is a ReefAPI endpoint group for dutch and belgian marketplace products, prices and competing sellers. It returns live JSON through POST requests under /bol/v1.

Is the bol.com API free to try?

Yes. ReefAPI starts with 1,000 free credits, no card required. bol.com calls use the same shared credit balance as every other ReefAPI engine.

Do I need a bol.com login or account?

No login to bol.com is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.

How fresh is the bol.com data?

The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.

How many credits does the bol.com API use?

bol.com actions currently cost 1-2 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.

Can I call bol.com from an AI assistant or MCP client?

Yes. Connect ReefAPI once through MCP and your assistant can call bol actions with the same key, credit pool and JSON envelope used by normal REST requests.

docs / bol

bol.com

Dutch and Belgian marketplace products, prices and competing sellers.

base /bol/v14 endpoints
post/bol/v1/product/detail2 credits

Full bol.com product by id (or by its url): title, brand, EAN and MPN, the buy-box price with bol's 90-day reference price and the discount, the seller, the delivery promise, the full image gallery, the complete specification table, the description as plain text, the category breadcrumb, the average rating and review count, and how many competing offers exist. Review TEXT is not returned - bol serves it only to a signed-in session, and this endpoint never invents it.

ParameterAllowed / rangeDescription
product_idrequiredbol product id - the long number at the end of a product url (bol.com/nl/nl/p/<slug>/9300000180008278/). A full product url works too: the words in the path are decoration and the number is the key. Every row `search` and `category` return carries both.
market = nloptionalnl · be · be-frWhich bol storefront to read: nl (bol.com/nl/nl, Dutch) - be (bol.com/be/nl, Belgian Dutch) - be-fr (bol.com/be/fr, Belgian French). One catalogue, three localised storefronts; prices are in EUR on all three and can differ between them.
max_rotations = 4optional1–10Advanced: how many times to retry a refused request (1-10, default 4). Leave unchanged for typical use.
Try in playground →
post/bol/v1/product/offers1 credit

Every seller offering one bol.com product, with that seller's price, condition, delivery promise, shipping cost and bol seller rating - bol is a marketplace and this is the competing-offer table behind the buy-box, on bol's own price-overview page. Cheap: about 45 KB per call against 290 KB for the product page.

ParameterAllowed / rangeDescription
product_idrequiredbol product id - the long number at the end of a product url (bol.com/nl/nl/p/<slug>/9300000180008278/). A full product url works too: the words in the path are decoration and the number is the key. Every row `search` and `category` return carries both.
market = nloptionalnl · be · be-frWhich bol storefront to read: nl (bol.com/nl/nl, Dutch) - be (bol.com/be/nl, Belgian Dutch) - be-fr (bol.com/be/fr, Belgian French). One catalogue, three localised storefronts; prices are in EUR on all three and can differ between them.
max_rotations = 4optional1–10Advanced: how many times to retry a refused request (1-10, default 4). Leave unchanged for typical use.
Try in playground →
post/bol/v1/category2 credits

Browse a bol.com category by its id, paginated - the same rich product row `search` returns, plus the category bol resolved and its breadcrumb. Category listings page far deeper than search does and their result total is exact rather than estimated.

ParameterAllowed / rangeDescription
category_idrequiredbol category id - the number in a category url (bol.com/nl/nl/l/laptops/4770/). A full category url works too. The NUMBER decides the category and the words are ignored, so /l/koptelefoons/4770/ really does serve Laptops; the response echoes the category bol resolved. `search` returns the ids of the categories its results fall into, under `categories`.
page = 1optional1–Result page, 1-based, ~30 products per page. Category browse pages go deep - the response reports `total_pages`.
sortoptionalrelevance · price_asc · price_descResult ordering. Only these three are published because only these three were measured to actually re-order bol's results; every other ordering the site offers is applied client-side and is not reachable from a request.
market = nloptionalnl · be · be-frWhich bol storefront to read: nl (bol.com/nl/nl, Dutch) - be (bol.com/be/nl, Belgian Dutch) - be-fr (bol.com/be/fr, Belgian French). One catalogue, three localised storefronts; prices are in EUR on all three and can differ between them.
max_rotations = 4optional1–10Advanced: how many times to retry a refused request (1-10, default 4). Leave unchanged for typical use.
Try in playground →