Skip to content
Scrappa Get API key
bol.com API 9 credits / request

bol.com Product Search API Documentation

GET https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150

Scrappa's GET /api/bol/search returns bol.com products for the Netherlands and Belgium as structured JSON, with sort, category, brand and price filters and paging.

Credits

One successful request with results costs 9 credits. An empty result, a validation error and every failure cost nothing.

What you get

One request returns one page (about 30 cards) with bol.com's own match count in total, max_page, the requested page and the facets for the next call. Each product has id, title, url, price (a number) and currency (EUR), original_price and discount (amount and percent) when bol.com shows a reference price, select_price, seller, condition, delivery_text, delivery_date (ISO 8601), image_url, rating, review_count, brand, categories, is_sponsored and offers_url. The id goes unchanged into the product, offers and reviews endpoints.

Storefronts

country=nl (default) searches bol.com Netherlands. country=be searches Belgium in Dutch (language=nl, default) or French (language=fr). A search for an EAN returns the product with that EAN.

Filters are honoured

category takes a category id from facets with type category. facet_ids takes filter value ids from facets (for example a brand), comma-separated. min_price and max_price filter by price in EUR; cards whose shown price is outside the range are removed from the page. applied_filters echoes what was sent. Unknown parameters and values return 422.

Sorting and paging

sort is relevance (default), price_asc, price_desc, rating or popularity. bol.com lists at most 10 pages. A later page returns an empty products list with the requested page, never page 1 data.

Not available

Rating and delivery filters are not offered. A bare brand name such as a brand without a product word returns 422.

bol.com Product Search API Documentation 9 credits / request

Endpoint

Request preview
GET
https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150
Auth header
x-api-key
Cost
9 credits / request
q = airfryer
Response preview
200 OK
{
    "success": true,
    "query": "airfryer",
    "locale": "nl/nl",
    "page": 1,
    "max_page": 10,
    "total": 704,
    "returned": 28,
    "applied_filters": {
        "sort": "price_asc",
        "min_price": 100,
        "max_price": 150
    },
    "products": [
...

Parameters

Start with the required fields, then add optional filters only when your use case needs them.

Runnable path

1 required parameter needed before sending a request.

8 optional filters available.

q string Required

Search term or EAN, for example airfryer.

Example value airfryer
country string Optional

nl (default) or be.

Example value nl
language string Optional

nl (default) or fr. fr needs country=be.

Example value en
page integer Optional

Result page, 1 to 10. Later pages are empty.

Example value 1
sort string Optional

relevance (default), price_asc, price_desc, rating or popularity.

Example value price_asc
category string Optional

Category id from the facets of an earlier search, for example 18336.

Example value example
facet_ids string Optional

Filter value ids from the facets, such as a brand. Comma-separated.

Example value example
min_price number Optional

Minimum price in EUR.

Example value 100
max_price number Optional

Maximum price in EUR.

Example value 150

Request Examples

PHP
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "x-api-key: YOUR_API_KEY_HERE"
    ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
    echo "cURL Error #:" . $err;
} else {
    echo $response;
}
PHP
<?php

use Illuminate\Support\Facades\Http;

$response = Http::timeout(30)
    ->withHeaders(['x-api-key' => 'YOUR_API_KEY_HERE'])
    ->get('https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150');

if ($response->successful()) {
    echo $response->body();
} else {
    echo "Error: " . $response->status();
}
JavaScript
const options = {
    method: 'GET',
    headers: {
        'x-api-key': 'YOUR_API_KEY_HERE'
    }
};

fetch('https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150', options)
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.text();
    })
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));
JavaScript
const axios = require('axios');

const options = {
    method: 'GET',
    url: 'https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150',
    headers: {
        x-api-key: 'YOUR_API_KEY_HERE',
    }
};

try {
    const response = await axios(options);
    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
Ruby
require 'net/http'
require 'uri'

uri = URI.parse("https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'

request = Net::HTTP::Get.new(uri.request_uri)
request['x-api-key'] = 'YOUR_API_KEY_HERE'

begin
    response = http.request(request)
    puts response.body
rescue => e
    puts "Error: #{e.message}"
end
Python
import http.client
import json

conn = http.client.HTTPSConnection("scrappa.co")

headers = {
    'x-api-key': 'YOUR_API_KEY_HERE',
}

try:
    conn.request("GET", "/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150", headers=headers)
    res = conn.getresponse()
    data = res.read()
    print(data.decode("utf-8"))
except Exception as e:
    print(f"Error: {e}")
finally:
    conn.close()
Python
import requests

headers = {
    'x-api-key': 'YOUR_API_KEY_HERE',
}

try:
    response = requests.get('https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150', headers=headers)
    response.raise_for_status()
    print(response.text)
except requests.exceptions.RequestException as e:
    print(f"Error: {e}")
Java
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;

public class ApiExample {
    public static void main(String[] args) {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
            .url("https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150")
        .addHeader("x-api-key", "YOUR_API_KEY_HERE")
            .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            } else {
                System.out.println("Error: " + response.code());
            }
        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
Go
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {
    client := &http.Client{}
    req, err := http.NewRequest("GET", "https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150", nil)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }
    req.Header.Set("x-api-key", "YOUR_API_KEY_HERE")

    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error making request:", err)
        return
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Error reading response:", err)
        return
    }

    fmt.Println(string(body))
}
Terminal
#!/bin/bash

curl -X GET \
    -H "x-api-key: YOUR_API_KEY_HERE" \
    "https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150"
C#
using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY_HERE");

        try
        {
            var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150"));
            var content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}
TypeScript
import axios from 'axios';

async function run(): Promise<void> {
    try {
        const response = await axios({
            method: 'GET',
            url: 'https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150',
            headers: {
        'x-api-key': 'YOUR_API_KEY_HERE',
            },
        });

        console.log(response.data);
    } catch (error) {
        console.error('Error:', error);
    }
}

void run();
RUST
use reqwest::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();

    let response = client
        .get("https://scrappa.co/api/bol/search?q=airfryer&country=nl&sort=price_asc&min_price=100&max_price=150")
        .header("x-api-key", "YOUR_API_KEY_HERE")
        .send()
        .await?;

    println!("{}", response.text().await?);

    Ok(())
}

Response Schema

Example response fields are illustrative; inspect the JSON before integrating.

Example response fields

Scan these fields before integrating.

success query locale page max_page total returned applied_filters +3 more

Common products fields

id title url price
JSON Response
200 OK
{
    "success": true,
    "query": "airfryer",
    "locale": "nl/nl",
    "page": 1,
    "max_page": 10,
    "total": 704,
    "returned": 28,
    "applied_filters": {
        "sort": "price_asc",
        "min_price": 100,
        "max_price": 150
    },
    "products": [
        {
            "id": "9300000171550609",
            "title": "Philips 3000 Series Dual Airfryer - NA351/00 - Dubbele Mand",
            "url": "https://www.bol.com/nl/nl/p/philips-3000-series-dual-airfryer-na351-00/9300000171550609/",
            "price": 109,
            "currency": "EUR",
            "original_price": 199.99,
            "discount": {
                "amount": 90.99,
                "percent": 45
            },
            "select_price": null,
            "is_select": false,
            "seller": {
                "id": "0",
                "name": "bol",
                "is_bol": true,
                "rating": null,
                "rating_percent": null,
                "top_seller": null
            },
            "condition": "new",
            "delivery_text": "Op voorraad. Voor 23:59 uur besteld, dinsdag in huis",
            "delivery_date": "2026-11-10",
            "image_url": "https://media.s-bol.com/Qr0jNQGR24Q0/zp9Z668/1200x989.jpg",
            "rating": 4.6,
            "review_count": 200,
            "brand": {
                "id": "4978545",
                "name": "Philips"
            },
            "categories": [
                [
                    {
                        "id": "3136",
                        "name": "Elektronica"
                    },
                    {
                        "id": "18336",
                        "name": "Airfryers"
                    }
                ]
            ],
            "is_sponsored": false,
            "offers_url": "https://www.bol.com/nl/nl/prijsoverzicht/philips-3000-series-dual-airfryer-na351-00/9300000171550609/",
            "locale": "nl/nl"
        }
    ],
    "facets": [
        {
            "type": "category",
            "id": "18336",
            "name": "Airfryers",
            "count": 2868,
            "applied": false
        },
        {
            "type": "range",
            "id": "12194",
            "name": "Prijs (\u20ac)",
            "min": 0.89,
            "max": 2203,
            "unit": "\u20ac"
        },
        {
            "type": "filter",
            "id": "4842",
            "name": "Merk",
            "items": [
                {
                    "id": "4294884369",
                    "name": "Philips",
                    "count": 72,
                    "applied": false
                }
            ]
        }
    ],
    "meta": {
        "endpoint_family": "search",
        "billable": true,
        "credits": 9,
        "attempts": 1
    }
}

Errors

Handle these documented responses before retrying or showing customer-facing failures.

422

Query Not Searchable

bol.com answers a bare brand name with a brand page instead of a product list (`unsearchable_query`). Add a product word. Non-billable.

{
    "meta": {
        "attempts": 1,
        "billable": false,
        "retryable": false,
        "endpoint_family": "search"
    },
    "error": {
        "code": "unsearchable_query",
        "message": "bol.com answers this query with a brand or category page, not a product list. Search for a product term instead."
    },
    "success": false
}
422

Validation Error

A query parameter is missing, unknown or unusable. Unknown parameters and unknown values are rejected, never ignored. Non-billable.

{
    "errors": {
        "q": [
            "The q field is required."
        ]
    },
    "message": "The q field is required."
}
503

Upstream Unavailable

bol.com could not be reached after retries, answered with an error or changed its format (`upstream_unavailable`, `upstream_blocked`, `parser_drift`). Retryable and never billed. Clients are never rate limited.

{
    "meta": {
        "attempts": 4,
        "billable": false,
        "retryable": true,
        "endpoint_family": "search"
    },
    "error": {
        "code": "upstream_unavailable",
        "message": "bol.com is temporarily unavailable. Please retry."
    },
    "success": false
}

Generate Code with AI

Copy a ready-made prompt with all the endpoint details, parameters, and example responses. Paste it into ChatGPT, Claude, or any AI assistant to instantly generate working code.

Try It Live

Test this endpoint in our interactive playground with real data.