Every Greek shop's price for one product, in one call
The Skroutz API turns Greece's price-comparison site into clean JSON, in three actions - search, product/detail and product/offers.
3 active endpoints. Every call is 1 credit.
- POST/skroutz/v1/search
- POST/skroutz/v1/product/detail
- POST/skroutz/v1/product/offers
What Skroutz endpoints does ReefAPI ship?
3 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Skroutz API
3 of 3 endpoints, ready to run
The whole merchant table for one product: each shop's Skroutz id, name, storefront link, star rating and rating count, its town and country, the price, the shipping fee, the total including shipping, the delivery estimate and the stock line.
{ "ok": true, "meta": { "api": "skroutz", "endpoint": "product/offers", "mode": "live", "latency_ms": 1224.9, "record_count": 14, "cache_hit": false }, "data": { "product": { "product_id": "809", "title": null, "brand": "Teka", "category": "Απορροφητήρες Κουζίνας", "url": "https://www.skroutz.gr/s/809", "price_min": 130, "price_max": 189, "price_min_display": "130,00 €", "price_max_display": "189,00 €", "currency": "EUR", "offer_count": 14, "offer_count_published": 14, "rating": null, "review_count": null, "rating_scale": null }, "offers": [ { "offer_id": "152976800", "seller": { "id": "2512", "name": "Couzina", "url": "https://www.skroutz.gr/shop/2512/Couzina/products.html", "rating": 5, "rating_count": 29, "location": "Ελευσίνα, Ελλάδα", "store_pickup": true, "official_reseller": true }, "price": 130, "price_display": "130,00 €", "price_before_discount": null, "discount": null, "currency": "EUR", "shipping_cost": 5.5, "shipping_display": "5,50 €", "free_shipping": false, "total_price": 135.5, "delivery_estimate": "έως Πέμ, 10 Σεπ", "stock": "1 τεμάχιο", "stock_quantity": 1, "offer_url": "https://www.skroutz.gr/products/show/152976800", "offer_title": "Teka GFH 73 Απορροφητήρας Τζακιού 73cm Εγγύηση 2+1 Χρόνια", "brand": "Teka", "promoted": true, "product_id": "809", "position": 1 }, { "offer_id": "24896001", "seller": { "id": "628", "name": "Web-electric", "url": "https://www.skroutz.gr/shop/628/products.html", "rating": null, "rating_count": null, "location": "Γαλάτσι, Ελλάδα", "store_pickup": false, "official_reseller": true }, "price": 133, "price_display": "133,00 €", "price_before_discount": null, "discount": null, "currency": "EUR", "shipping_cost": 6, "shipping_display": "6,00 €", "free_shipping": false, "total_price": 139, "delivery_estimate": "Ετοιμάζεται για αποστολή σε 2 ημέρες", "stock": null, "stock_quantity": null, "offer_url": "https://www.skroutz.gr/products/show/24896001", "offer_title": "Teka GFH-73 Inox Μηχανισμος Απορρόφησης", "brand": "Teka", "promoted": false, "product_id": "809", "position": 2 }, { "offer_id": "244055862", "seller": { "id": "8485", "name": "Clubelectric", "url": "https://www.skroutz.gr/shop/8485/Clubelectric/products.html", "rating": null, "rating_count": null, "location": "Ασπρόπυργος, Ελλάδα", "store_pickup": true, "official_reseller": false }, "price": 135, "price_display": "135,00 €", "price_before_discount": null, "discount": null, "currency": "EUR", "shipping_cost": 5.5, "shipping_display": "5,50 €", "free_shipping": false, "total_price": 140.5, "delivery_estimate": "έως Τετ, 09 Σεπ", "stock": "2 τεμάχια", "stock_quantity": 2, "offer_url": "https://www.skroutz.gr/products/show/244055862", "offer_title": "Teka GFH 73 Μηχανισμός Απορρόφησης 73cm Inox", "brand": "Teka", "promoted": false, "product_id": "809", "position": 3 } ], "count": 14, "cheapest": 130, "most_expensive": 189 } }
How the Skroutz API works
Skroutz 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 192 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.
Find a product, then get every Greek shop selling it — and the real price floor
The search row gives you one number, and it is not the cheapest one: Skroutz prints the offer it features. The comparison itself is the second call, and on this engine that call is also the cheaper of the two.
{"query": "καφετιέρα espresso"}One page of products. Take results[].product_id. The response also carries Skroutz's own total_results, and tells you whether Skroutz answered your keyword with one of its own category or brand pages.
{"product_id": "46364858"}One upstream request, no pagination to chase: every Greek merchant for that product with price, shipping, total, delivery date and the shop's own star rating. This is where price_min and price_max are real numbers.
{"product_id": "46364858"}The catalogue side: brand, MPN, model, colour, the per-star rating breakdown and the full Greek spec table.
Three flat credits for a keyword, the full Greek merchant table for a product, and the catalogue record behind it — with the merchant table costing about half the bytes of the product page rather than several times more.
curl -X POST https://api.reefapi.com/skroutz/v1/product/offers \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"product_id":"809"}'{
"ok": true,
"data": { … },
"meta": {
"api": "skroutz",
"endpoint": "product/offers",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}The price on a Skroutz product page is the FEATURED offer, not the cheapest one
This is the single most important thing to know before you build against Skroutz, and it is why price_min is deliberately null on product/detail. Skroutz prints one price on a product page and on a listing card: the offer it features. Checked against the same product's own merchant table on all 13 verification products on 2026-09-06, that price equalled the cheapest offer on 6 and sat ABOVE it on 7. It is always one of the real offer prices - it is honest data - but calling it a price floor would be a lie by field name.
| Skroutz product | Price on the product page | Cheapest merchant offer | Where the featured offer ranked |
|---|---|---|---|
| Bosch Mymoment TKA2M113 filter coffee maker | 41.52 EUR | 37.79 EUR | 16th of 29 offers - the worst case measured |
| Apple iPhone 17 Pro Max | 1,370.00 EUR | 1,362.40 EUR | 2nd of 48 |
| LG Smart 32-inch Full HD TV | 192.90 EUR | 191.52 EUR | 3rd of 33 |
| New Balance 530 | 109.00 EUR | 108.99 EUR | 2nd of 43 |
| Nike Air Force 1 '07 | 108.00 EUR | 107.96 EUR | 2nd of 39 |
| Samsung Smart 43-inch 4K QLED | 286.00 EUR | 285.86 EUR | 2nd of 29 |
| Ulefone Armor 28 Ultra 5G | 944.90 EUR | 944.88 EUR | 2nd of 36 |
So product/detail returns that number as price and returns price_min, price_max and offer_count as null, pointing at product/offers - which is the only surface where the real band and the real count exist. product/offers returns both, and its count matched the shop count Skroutz prints on its own merchant table on 10 of the 10 products where Skroutz prints one (14/14, 9/9, 29/29, 29/29, 33/33, 36/36, 39/39, 43/43, 48/48, 49/49). That parity is what establishes there is no hidden pagination to chase.
Which country, which id, which currency, and how many shops you actually get
skroutz.gr only — one country, one currency, and a product id that is a bare number. Measured on 2026-09-06 across 13 products in 8 Skroutz categories and 332 merchant offers, plus the live calls behind this page. Four of these lines go against us.
This engine reads skroutz.gr. Prices, shipping fees, delivery dates and shop ratings are all Greek-scoped, the currency is EUR on every row, and there is no country parameter because there is no other storefront behind it. Shop locations come back as the town and country the shop ships from, and a few of them are outside Greece — one verification row read "Ρουμανία" — so cross-border sellers are visible rather than hidden.
A Skroutz product URL looks like /s/809/Teka-GFH-73-Michanismos-Aporrofisis-73cm-Inox.html and only the 809 matters: any slug resolves and Skroutz redirects to its canonical one. Every search row hands that number back as product_id and every product action takes the number or the full URL. Because a wrong slug still resolves, the engine additionally checks that the id Skroutz finally served is the id you asked for before it returns anything — so a redirect can never hand you a different product's record.
As many as Skroutz lists, in ONE upstream request — there is no pagination on the merchant table. Measured on 2026-09-06: 49 shops on a De'Longhi descaler at 382 KB and 1.5 s, 48 on an iPhone 17 Pro Max, 43 on a New Balance 530, 14 on the Teka reference product at 102 KB and 0.96 s, and 21 KB with 0.63 s where only one shop sells the product. The median across all 13 was 231 KB and 1,425 ms, which makes offers the CHEAPEST of the three actions — a product page is 429 KB median. All three are flat-rated at one credit.
Skroutz prints its own shop count on the merchant table ("14 Καταστήματα"). On the 10 verification products where it prints one, the number of offers returned equalled it 10 times out of 10 — 9/9, 14/14, 29/29, 29/29, 33/33, 36/36, 39/39, 43/43, 48/48 and 49/49. That parity is the check that establishes there is no hidden second page of merchants quietly being dropped. The other three products had a single merchant, for which Skroutz prints no count at all.
Skroutz prints one price on a product page and on a listing card, and it is the offer it puts in its own buy-box. Checked against the same product's merchant table on all 13 verification products, that price equalled the cheapest offer on 6 and sat ABOVE it on 7 — worst case 41.52 EUR against a cheapest offer of 37.79, which was rank 16 of 29. It is always one of the real offer prices, so it is honest data, but naming it a price floor would be a lie by field name. So product/detail returns price_min, price_max and offer_count as explicit nulls and points at product/offers, which is the only surface where the band and the count exist.
A card covering a family of sibling products — a television sold in 43 to 98 inches — prints "285,86 € - 1.999,00 €" rather than a price. On the television category page 33 of 48 cards were in that state. A first-number-wins parser returns 33 confident wrong prices there and a strict one returns 33 nulls that look like 69% field loss, so instead price comes back null, the two endpoints go into price_from and price_to, variant_family is set, and price_display always carries exactly the string Skroutz printed. Between price and price_to every row on every page measured was accounted for: 48/48 televisions, 52/52 perfumes, 57/57 laptops, 55/55 washing machines.
There is no maximum-rating value in the page or in its structured data, so rating_scale comes back null on every action rather than an assumed 5. What you get instead is the per-star histogram itself — 1 through 5 with the count in each bucket — so you can read the shape of a 4.7 first-hand instead of taking our word for the denominator. The same discipline covers unrated shops: 80 of the 332 measured offers came from shops Skroutz has not rated, and those return null for the rating and the rating count, never a flattering 0.0.
There is no deep link into the merchant's own product page, because Skroutz does not publish one — the offer link is Skroutz's click-through, which is all the site itself exposes. Stock is the same: where a shop declares "5+ τεμάχια" the text is returned and the numeric quantity stays null rather than being rounded down to 5. And a price is per product, not per size, because that is how Skroutz prices — a sneaker in twelve sizes is one price and one row.
A second extractor written independently over the raw page, sharing no code with the parser, agreed with the engine on 332 of 332 offer rows — 0 price mismatches. The two rows where the two disagreed at all were merchant NAMES, and there the engine was the more correct one because it decodes HTML entities. That check matters because of a specific trap: a merchant row carries a pre-coupon number next to the rendered one, and on a row with a running coupon they differ by the coupon — 799,00 against 759,05 on one verification row. Reading the wrong one ships a price 39.95 EUR too high while still returning ok:true. 3 of the 332 rows were in that state, and price_before_discount and discount carry the rest of the story.
Skroutz answers broad keywords with its own category or brand pages — "laptop" becomes its laptops category — and it drops the page number on the way, so a naive page 2 returns page 1 again. The response says which happened, with the resolved title and URL, and paging works either way. Sponsored cards are re-injected across pages, so consecutive pages overlap slightly and a caller sweeping a category should de-duplicate on product_id; duplicates within a single page are already dropped and counted. A keyword can also land on an editorial article with no products on it at all, which comes back as an honest count of 0 rather than an error.
What people build with Skroutz
The jobs this data is most often used for.
endpoints
credit per call
Greek price-monitoring teams call product/offers to get every merchant's price, shipping fee, total and delivery date for one product in a single request.
Repricing tools read price_min and price_max from product/offers rather than the product page, because the page price was above the cheapest offer on 7 of 13 measured products.
Marketplace sellers check where their own Skroutz offer ranks among up to 49 competitors, with each shop's star rating and rating count attached.
Catalog teams call product/detail for the Greek title, brand, MPN, model, colour and the full spec table grouped exactly as Skroutz groups it.
What Skroutz 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 192 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/skroutz/v1/product/offers \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"product_id":"809"}'import requests
r = requests.post(
"https://api.reefapi.com/skroutz/v1/product/offers",
headers={"x-api-key": REEF_KEY},
json={
"product_id": "809"
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Skroutz.
Get a free key →How many Greek shops does one product/offers call return, and what does it cost?▾
As many as Skroutz lists, in a single upstream request - there is no pagination on the merchant table. Measured on 2026-09-06: 49 shops on a De'Longhi descaler (382 KB, 1.5 s), 48 on an iPhone 17 Pro Max (361 KB, 1.4 s), 43 on a New Balance 530, 36 on a Ulefone Armor 28 Ultra, 14 on the Teka GFH 73 reference product (102 KB, 0.96 s). A single-merchant product is 21 KB and 0.63 s. Median across the 13 products was 231 KB and 1,425 ms. That makes offers the CHEAPEST of the three actions on bytes - a product page is 429 KB median - which is unusual for a price-comparison site and is the reason it is priced the same as the other two rather than above them.
Is the price on a search row or a product page the cheapest price?▾
No. It is the offer Skroutz features, and it was above the cheapest merchant offer on 7 of the 13 verification products - once by 10 percent, at rank 16 of 29. On a listing card the same rule holds: a card reading 120,00 EUR sat on a product whose cheapest merchant offer was 108,99 EUR. If you need a floor, call product/offers and read price_min there; that action returns the real band and its cheapest and most expensive rows. product/detail returns price_min, price_max and offer_count as explicit nulls so you cannot mistake the featured price for a band.
Why is price null on some search rows?▾
Because that card is a variant family and Skroutz printed a RANGE instead of a price - "285,86 EUR - 1.999,00 EUR" for a TV sold in 43 to 98 inches. Measured on the television category page: 33 of 48 cards were in that state. A first-number-wins parser would return 33 confident wrong prices there, so the engine returns price as null, puts the two endpoints in price_from and price_to, sets variant_family to true, and always returns price_display with exactly the string Skroutz printed. Between price and price_to, every row on every page measured was accounted for: 48/48 TVs, 52/52 perfumes, 57/57 laptops, 55/55 washing machines.
Does the merchant price include a coupon discount?▾
Yes, and this one is a trap in the raw page. Each merchant row carries a data attribute with a pre-coupon price, and on a row with a running coupon that number is wrong: the rendered price was 759,05 EUR, the struck-through price 799,00 EUR and the coupon 39,95 EUR. Reading the attribute would ship a price 39.95 EUR too high while returning ok:true. The engine reads the rendered final price instead and returns price_before_discount and discount alongside it. 3 of the 332 measured offer rows were in that state - rare, and exactly the rows a customer would notice.
Why does a search sometimes return a category page instead of search results?▾
Because Skroutz answers broad keywords with one of its own pages - "laptop" becomes its laptops category, "samsung" becomes its Samsung brand page - and it drops the page number on the way, so asking for page 2 of a redirected keyword returns page 1 again. The engine detects that and re-requests from the resolved URL, so paging works either way; it costs one upstream request when Skroutz stays on its search route and two when it redirects. The response tells you which happened: search_mode reads keyword or resolved, with resolved_title and resolved_url. A keyword can also resolve onto an editorial article, which carries no product cards at all - that comes back as an honest count of 0 with the article URL, not as an error.
How reliable is the parsed price - has it been checked against the page?▾
Twice, independently. A second extractor written as raw regex over each merchant block, sharing no code with the engine's parser, agreed on 332 of 332 offer rows. The only two rows where the two disagreed at all were merchant NAMES, and there the engine was the more correct one - it decodes HTML entities, so it returns "Woman's Fashion" and "Web & IT" where the naive extractor returns the escaped text. A recursive scan of every string in all 26 verification payloads found 0 raw HTML tags and 0 HTML entities.
Is a shop rating of zero a real rating?▾
There is never a zero. 252 of 332 measured offers carried a shop rating; the other 80 came from shops Skroutz has genuinely not rated, and those return null for both the rating and the rating count, never 0.0. The invariant was checked directly - 0 rows had a null rating sitting next to a non-null rating count. Note also that a shop's rating and a product's rating are two different numbers and are returned in two different places: on one verification product the item had a review_count of 6 while its single seller had a rating_count of 3.
What does Skroutz NOT publish?▾
A rating scale, first of all: there is no maximum-rating value anywhere in the page or its structured data, so rating_scale is null on every action rather than an assumed 5. What you get instead is the per-star histogram itself, so you can read the buckets first-hand. Also absent: a price band or shop count on the product page (both live on product/offers), a link into the merchant's own site - the only link Skroutz exposes is its own click-through - an exact stock number when the shop declares a band like "5+ pieces" (the text is returned, the number stays null), a per-size price, since Skroutz prices the product rather than the size, and a shop rating for an unrated shop. Skroutz also has no stable search page size; it returns 48 to 60 rows depending on the page it resolved to, so read count.
What is the Skroutz API?▾
Skroutz API is a ReefAPI endpoint group for greek price comparison: every greek shop's price for one product. It returns live JSON through POST requests under /skroutz/v1.
Is the Skroutz API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Skroutz calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Skroutz login or account?▾
No login to Skroutz 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 Skroutz 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 Skroutz API use?▾
Skroutz actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Skroutz from an AI assistant or MCP client?▾
Yes. Connect ReefAPI once through MCP and your assistant can call skroutz actions with the same key, credit pool and JSON envelope used by normal REST requests.
43 E-commerce & Marketplaces APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Skroutz, 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 191 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.