Netherlands and Belgium marketplace data, with the seller table as the cheap call
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 active endpoints, on 1 and 2 credit tiers.
- POST/bol/v1/search
- POST/bol/v1/product/detail
- POST/bol/v1/product/offers
- POST/bol/v1/category
What bol.com endpoints does ReefAPI ship?
4 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
bol.com API
4 of 4 endpoints, ready to run
Every seller offering one product, with that seller's price, condition, offer type, shipping cost, delivery promise and bol's own 1-to-10 seller rating, plus a count of new, refurbished and second-hand offers.
{ "ok": true, "meta": { "api": "bol", "endpoint": "product/offers", "mode": "live", "latency_ms": 1240.2, "record_count": 6, "cache_hit": false }, "data": { "product": { "product_id": "9300000165727120", "title": "Anker soundcore Space One Draadloze Headset - Noise Cancelling - Zwart", "url": "https://www.bol.com/nl/nl/p/soundcore-by-anker-space-one-koptelefoon-met-adaptieve-en-actieve-ruisonderdrukking-2x-zo-sterke-stemmendemping-40-u-speeltijd-appbediening-ldac-hi-res-wireless-audio-comfortabel-bluetooth-5-3/9300000165727120/", "image": "https://media.s-bol.com/Jmzj34xYr7V9/gLQKvRY/147x210.jpg" }, "offers": [ { "offer_id": "51fb11e5-e947-40a4-a50d-caf56a2c523f", "price": 84, "currency": "EUR", "reference_price": null, "discount_percent": null, "discount_amount": null, "condition": "new", "offer_type": "STANDARD", "seller": { "id": "1821256", "name": "Anker Direct", "is_bol": false, "rating": 8.7, "rating_count": null, "top_seller": false }, "delivery": { "description": "Op voorraad. Voor 23:59 uur besteld, morgen in huis", "arrives_by": "2026-09-07", "release_date": null, "shipping_cost": 0, "within_48h": true }, "low_stock": false, "promotions": [ "Select-deal" ] }, { "offer_id": "b90b9f9d-a6dc-4a0d-b7bb-dc5805d176fe", "price": 84.65, "currency": "EUR", "reference_price": null, "discount_percent": null, "discount_amount": null, "condition": "new", "offer_type": "STANDARD", "seller": { "id": "1506674", "name": "ASD", "is_bol": false, "rating": 8.7, "rating_count": null, "top_seller": false }, "delivery": { "description": "Uiterlijk 17 september in huis", "arrives_by": "2026-09-17", "release_date": null, "shipping_cost": 0, "within_48h": false }, "low_stock": false, "promotions": null }, { "offer_id": "f4b0f43d-fce0-4a14-96bd-ae7c05643bd9", "price": 87.36, "currency": "EUR", "reference_price": null, "discount_percent": null, "discount_amount": null, "condition": "new", "offer_type": "STANDARD", "seller": { "id": "1045224", "name": "gsmpunt", "is_bol": false, "rating": 8.7, "rating_count": null, "top_seller": false }, "delivery": { "description": "Op voorraad. Voor 23:59 uur besteld, dinsdag in huis", "arrives_by": "2026-09-08", "release_date": null, "shipping_cost": 0, "within_48h": true }, "low_stock": false, "promotions": null } ], "count": 6, "offer_counts": { "new": 6, "refurbished": 0, "secondhand": 0 } } }
How the bol.com API works
bol.com is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 188 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
Compare one product's price across the Dutch and Belgian storefronts, and see who sells it
bol runs three storefronts over one catalogue of product ids, and the same id can be a different price on each. That makes the cross-border comparison a two-call job with no id mapping in between.
{"query": "koptelefoon", "market": "nl", "sort": "price_asc"}Two credits. Take products[].product_id - the same id works on every storefront, so nothing has to be re-resolved.
{"product_id": "9200000032872507", "market": "be"}Two credits, and the point of the exercise. Re-run for this page, this product was 15.00 EUR on the Dutch storefront and 13.05 EUR on the Belgian one.
{"product_id": "9300000165727120", "market": "nl"}One credit - the cheapest action on the engine and about a sixth of a product page upstream. Every competing seller with its price, condition, shipping cost and bol rating.
Five credits for a Dutch listing, the same product priced on both sides of the border, and the full competing-seller table behind it.
curl -X POST https://api.reefapi.com/bol/v1/product/offers \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"product_id":"9300000180008278"}'{
"ok": true,
"data": { … },
"meta": {
"api": "bol",
"endpoint": "product/offers",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}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.
| Behaviour | Measured | What to do |
|---|---|---|
| NL and BE are different prices, not different languages | product 9200000032872507 was 15.00 EUR on the Dutch storefront and 13.05 EUR on both Belgian storefronts, in the same minute | treat 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 page | product/offers has a median of 1,224 ms against 1,550 ms for product/detail, and moves 45-48 KB against 288 KB | if 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 decoration | the same product resolves under any slug, and a category URL carrying the koptelefoons slug with id 4770 serves Laptops - because 4770 IS Laptops | pass 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 not | search page 11 returns 0 rows and a total of 0. The Laptops category reported 114 pages | the 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 so | one query's total moved between 10,006 and 60,468 on identical calls; large categories clamp at exactly 300,000 | read total_results_is_estimate before you put the number in a report |
| EAN is on the product, not on the listing row | 0 of 199 listing rows carried an EAN; product/detail returned a real one on 7 of 7 products checked, one per department | bol 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 bite | price 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 order | only 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.
Which storefronts, which id, which currency, and where the numbers are estimates
Three storefronts over one id space, one currency, and a competing-seller table that costs less than a product page. Measured on 2026-09-06 across 135 live calls, 199 products in 7 departments and all three storefronts, plus the live calls behind this page. Four of these lines go against us.
This is the reason market is a real parameter. Re-measured live for this page: a Sony MDR-ZX110 headphone was 15.00 EUR on the Dutch storefront and 13.05 EUR on the Belgian one, on the same product id, in the same minute. be and be-fr are the Dutch and French storefronts of Belgium, and a French search returns French titles and French category names for the same ids. If you are price-monitoring the Benelux you need both countries, not a translation.
All three storefronts quote EUR, so unlike a multi-country marketplace there is no conversion question here - a cross-border difference is a real price difference rather than an exchange-rate artefact. That is what makes the two-call comparison above meaningful.
A bol URL carries a slug, but only the numeric id resolves it, and every action takes the bare id or a full URL. The same holds for categories, and there it is a trap: a category URL carrying the koptelefoons slug with id 4770 serves Laptops, because 4770 IS Laptops. So the category action echoes bol's own name for what it actually resolved, which makes a wrong id visible instead of silent - three guessed ids during the build resolved to some other category rather than failing.
bol publishes its whole competing-offer table on its own page, and that page is far smaller than a product page - measured at a median of 1,224 ms and 45-48 KB against 1,550 ms and 288 KB for product/detail. It is priced accordingly, at one credit against two. If what you want is who sells it and for how much, go straight there rather than reading the product first.
A measured call on an Anker headset returned 6 sellers between 84.00 and 92.71 EUR - Anker Direct, ASD, gsmpunt, Eufy Official, bol itself and IT Distributie - each with price, condition, shipping cost, the date it arrives, whether that is within 48 hours, and a bol seller rating out of 10 (8.7, 8.4, 9.3 on those rows). bol's own row has no rating, because bol is not one of its own marketplace partners; that comes back null with an explicit is-bol flag rather than a flattering default. Across a seven-product chain the action returned 1, 1, 1, 1, 2, 3 and 6 offers.
Search page 11 returns 0 rows and a total of 0, so the limit is published on the parameter and page 11 is rejected rather than charged for; category browse pages far deeper, with one measured category reporting 114 pages. And the total itself is not always a fact: bol flags some searches as early-terminated and the number then moves between identical calls - one query measured at 10,006 and then 60,468 - while very large categories clamp at exactly 300,000. The response carries an explicit is-estimate flag so you know which kind of number you are holding.
0 of 199 measured listing rows carried an EAN, in any department. That is bol's shape rather than a parse gap - a listing card ships a summary spec block and zero spec groups, and EAN lives in a group. product/detail has it, and it was real on 7 of 7 products checked, one per department. If you are building a catalogue keyed on EAN, budget the second call.
Brand was filled on 5 of 30 rows in the books department, because a book has no brand on bol - it has an author, which bol publishes as a specification. Films filled 28 of 28 with a real distributor name, so the field itself works. Ratings behave the same way: 6 of 28 film rows had one, because most of those titles have no reviews yet. Written down rather than averaged away.
What looks like an RRP is bol's own reference price, which bol defines 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 a manufacturer's list price - which bol does not publish anywhere in the payload.
bol models a colour or a size as its own product id rather than as a variant of one. product/detail returns those siblings with the feature that distinguishes them, so you can walk to them, but there is no size matrix to read and none is invented - and it means price and seller can differ per colour. Separately, 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 value you get is the value that storefront publishes; inventing a canonical one would be fabricating it.
bol publishes a delivery promise, a latest-arrival date and a scarcity flag, and there is no stock number anywhere in the payload. Review text sits behind an authenticated call that answers 403 without a session, so only the average rating and the review total are returned. Seller address, chamber-of-commerce number and phone live on a separate bol page this engine does not read. All of it comes back null with the reason, rather than estimated.
135 live calls across three separate runs came back 135 successful, median around 1.8 to 2.2 seconds; per action, offers 1,224 ms, detail 1,550 ms, search 2,219 ms, category 2,694 ms. The tail is real and is stated rather than hidden: one search in 135 took 17.2 seconds. An occasional block is typed as retryable so it is retried rather than surfaced as a dead end. No storefront is meaningfully slower than another.
What people build with bol.com
The jobs this data is most often used for.
endpoints
credits per call
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.
What bol.com data costs
The cheapest call here is 1 credit, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 188 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/bol/v1/product/offers \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"product_id":"9300000180008278"}'import requests
r = requests.post(
"https://api.reefapi.com/bol/v1/product/offers",
headers={"x-api-key": REEF_KEY},
json={
"product_id": "9300000180008278"
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up bol.com.
Get a free key →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.
39 E-commerce & Marketplaces APIs on the same key
One key, one credit pool, one response envelope. If you are pulling bol.com, you are one call away from the rest of the category — no second contract, no second integration.
Need something this API does not do?
Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 187 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-09-06.