GET /best-sellers

Best Sellers

Rank Mercadona products by Mercadona's own popularity score for any Spanish postal code, filterable by category, brand and price.

Mercadona API

Returns Mercadona products ordered by Mercadona’s internal popularity ranking (popularity_score, highest first) at the warehouse that serves a postal code. Each row adds a rank that runs continuously across pages and a category_rank within the product’s category. Filter by category, brand or price range to get the top sellers of a segment.

HTTP Request

GET /best-sellers

Parameters

ParameterTypeRequiredDefaultDescription
warehousestringNovlc1Hub or 4-digit store code (see Warehouses ). Ignored when postal_code is given. Numeric store codes are served live: brand, ean, category_path and popularity_score may be null on their rows
postal_codestringNo-Spanish 5-digit postal code, resolved to the warehouse that serves it. Takes precedence over warehouse
pageintegerNo11-indexed page
per_pageintegerNo20Items per page, max 20
category_idintegerNo-Category id at any level (see Category Tree )
brandstringNo-Exact brand name as Mercadona writes it (see Brands ). Several brands comma-separated are OR-ed (Danone,Puleva). With one brand the list matches Brand Products in popularity order, plus rank
min_pricenumberNo-Lowest price_value in euros, inclusive, 0 to 10000 (e.g. 2 or 1.5). total counts only products in the range; products without a price are left out when a bound is set
max_pricenumberNo-Highest price_value in euros, inclusive, 0 to 10000. Must be greater than or equal to min_price
freshbooleanNofalseBypass the 15-minute cache. Only affects answers with source: live; catalog_index answers come from the daily catalog snapshot (snapshot_date) and refresh once a day
languagestringNoesLanguage for product and category names: es, en or ca

Response

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{
  "status": true,
  "request_id": "82da857d-8d62-197f-9877-599bdc4b",
  "cached_at": null,
  "data": {
    "items": [
      {
        "product_id": "3819",
        "name": "Plátano de Canarias IGP",
        "slug": "platano-canarias-igp-pieza",
        "url": "https://tienda.mercadona.es/product/3819/platano-canarias-igp-pieza",
        "thumbnail": "https://prod-mercadona.imgix.net/images/e4a37940916985bf5ca166e266580c37.jpg?fit=crop&h=300&w=300",
        "packaging": "Pieza",
        "main_feature": null,
        "is_water": false,
        "requires_age_check": false,
        "category": {
          "category_id": 1,
          "name": "Fruta y verdura"
        },
        "availability": {
          "in_stock": true,
          "status": null,
          "unavailable_from": null,
          "unavailable_weekdays": [],
          "order_limit": 999
        },
        "price": "0.45",
        "price_value": 0.45,
        "previous_price": null,
        "previous_price_value": null,
        "is_price_drop": false,
        "unit_price": "2.800",
        "unit_price_value": 2.8,
        "unit_price_format": "kg",
        "bulk_price_value": 2.8,
        "size_format": "kg",
        "unit_size": 0.16,
        "is_pack": false,
        "pack_size": null,
        "total_units": null,
        "unit_name": null,
        "iva_percent": 4,
        "approx_size": true,
        "drained_weight": null,
        "currency": "EUR",
        "color_variants": null,
        "warehouse": "vlc1",
        "ean": "2105410038198",
        "brand": null,
        "category_path": [
          [
            {
              "category_id": 1,
              "name": "Fruta y verdura",
              "level": 0
            },
            {
              "category_id": 27,
              "name": "Fruta",
              "level": 1
            }
          ]
        ],
        "popularity_score": 167499.0,
        "category_rank": 1,
        "rank": 1
      },
      {
        "product_id": "3824",
        "name": "Banana",
        "slug": "banana-pieza",
        "url": "https://tienda.mercadona.es/product/3824/banana-pieza",
        "thumbnail": "https://prod-mercadona.imgix.net/images/69edef3541bbf3f4b7173c9d617a5698.jpg?fit=crop&h=300&w=300",
        "packaging": "Pieza",
        "main_feature": null,
        "is_water": false,
        "requires_age_check": false,
        "category": {
          "category_id": 1,
          "name": "Fruta y verdura"
        },
        "availability": {
          "in_stock": true,
          "status": null,
          "unavailable_from": null,
          "unavailable_weekdays": [],
          "order_limit": 999
        },
        "price": "0.21",
        "price_value": 0.21,
        "previous_price": null,
        "previous_price_value": null,
        "is_price_drop": false,
        "unit_price": "1.250",
        "unit_price_value": 1.25,
        "unit_price_format": "kg",
        "bulk_price_value": 1.25,
        "size_format": "kg",
        "unit_size": 0.17,
        "is_pack": false,
        "pack_size": null,
        "total_units": null,
        "unit_name": null,
        "iva_percent": 4,
        "approx_size": true,
        "drained_weight": null,
        "currency": "EUR",
        "color_variants": null,
        "warehouse": "vlc1",
        "ean": "2105433038243",
        "brand": null,
        "category_path": [
          [
            {
              "category_id": 1,
              "name": "Fruta y verdura",
              "level": 0
            },
            {
              "category_id": 27,
              "name": "Fruta",
              "level": 1
            }
          ]
        ],
        "popularity_score": 135765.0,
        "category_rank": 2,
        "rank": 2
      }
    ],
    "total": 4338,
    "page": 1,
    "per_page": 2,
    "total_pages": 2169,
    "has_next_page": true,
    "source": "catalog_index",
    "snapshot_date": "2026-10-14",
    "resolved_filters": {
      "warehouse": {
        "input": "46001",
        "resolved": "vlc1",
        "source": "postal_code"
      }
    },
    "language": "es"
  },
  "request_params": {
    "postal_code": "46001",
    "per_page": "2"
  }
}

Response Fields

FieldTypeDescription
statusbooleantrue on success
request_idstringUnique request identifier
cached_atstring | nullISO timestamp when the answer came from cache, null when fetched for this request
dataobjectResponse payload
data.items[]array of objectsProducts ordered by popularity_score, highest first
data.items[].product_idstringMercadona product id. Pass it verbatim: decimal ids like 81241.3 exist
data.items[].namestringProduct name, translated with language
data.items[].slugstringURL slug of the product
data.items[].urlstringProduct URL on tienda.mercadona.es
data.items[].thumbnailstringProduct image URL (imgix)
data.items[].packagingstring | nullPackaging, e.g. "Tableta", "Botella", "Pieza"
data.items[].main_featurestring | nullHighlighted feature shown under the name
data.items[].is_waterbooleanWater product flag
data.items[].requires_age_checkbooleanAlcohol or other age-restricted product
data.items[].categoryobjectLevel-0 category of the product
data.items[].category.category_idintegerLevel-0 category id
data.items[].category.namestringLevel-0 category name, translated with language
data.items[].availabilityobjectAvailability at the resolved warehouse
data.items[].availability.in_stockbooleanIn stock at the resolved warehouse
data.items[].availability.statusstring | nullRestriction status, null when there is none
data.items[].availability.unavailable_fromstring | nullDate the product stops being available
data.items[].availability.unavailable_weekdaysarrayWeekdays the product can’t be delivered
data.items[].availability.order_limitintegerMaximum units per order (e.g. 999)
data.items[].pricestringDisplay price in EUR, e.g. "1.25"
data.items[].price_valuefloatNumeric price in EUR
data.items[].previous_pricestring | nullPrevious display price, null when there is none
data.items[].previous_price_valuefloat | nullPrevious numeric price in EUR
data.items[].is_price_dropbooleantrue when the current price is below previous_price. Computed from the previous price, not Mercadona’s own flag
data.items[].unit_pricestringDisplay unit price, e.g. "0.800"
data.items[].unit_price_valuefloatNumeric unit price
data.items[].unit_price_formatstringUnit the unit price refers to, e.g. "L", "kg", "ud"
data.items[].bulk_price_valuefloatBulk price
data.items[].size_formatstringSize unit, e.g. "l", "kg"
data.items[].unit_sizefloatSize in size_format units
data.items[].is_packbooleanWhether the product is a pack
data.items[].pack_sizefloat | nullSize of each unit in the pack
data.items[].total_unitsinteger | nullUnits in the pack
data.items[].unit_namestring | nullUnit name, e.g. "ud.", "briks"
data.items[].iva_percentintegerVAT percentage
data.items[].approx_sizebooleanSize is approximate (e.g. fruit sold by the piece)
data.items[].drained_weightfloat | nullDrained weight
data.items[].currencystringAlways "EUR"
data.items[].color_variantsarray | nullColour variants
data.items[].warehousestringWarehouse that answered
data.items[].eanstring | nullEAN barcode. Can be null (always possible on numeric store codes)
data.items[].brandstring | nullBrand name as Mercadona writes it. Can be null, e.g. for unbranded fresh produce
data.items[].category_patharray of arraysCategory paths. Each path is a list of {category_id, name, level} objects from level 0 down. Can be empty
data.items[].category_path[][].category_idintegerCategory id
data.items[].category_path[][].namestringCategory name, translated with language
data.items[].category_path[][].levelintegerCategory level: 0, 1 or 2
data.items[].popularity_scorefloat | nullMercadona’s internal popularity score. null on numeric store codes
data.items[].category_rankintegerPosition of the product within its category by popularity
data.items[].rankintegerOverall position in this list. Continuous across pages (page 2 with per_page=20 starts at 21)
data.totalintegerProducts ranked (within the filters, if set)
data.pageintegerCurrent page (1-indexed)
data.per_pageintegerItems per page
data.total_pagesintegerTotal number of pages
data.has_next_pagebooleanWhether another page follows
data.sourcestringData origin: catalog_index (daily catalog snapshot) or live
data.snapshot_datestringDate of the catalog snapshot used
data.resolved_filters.warehouseobjectThe warehouse that answered
data.resolved_filters.warehouse.inputstring | nullThe postal_code or warehouse you sent, null if none
data.resolved_filters.warehouse.resolvedstringWarehouse code used, e.g. mad3
data.resolved_filters.warehouse.sourcestringHow it was chosen: postal_code, param or default
data.languagestringLanguage used for names: es, en or ca
request_paramsobjectThe query parameters you sent, echoed back as strings

Error Responses

Invalid input returns HTTP 400, and error is a plain string:

1
2
3
4
5
6
7
8
{
  "status": false,
  "request_id": "b757e855-4127-3b96-509a-8b573904",
  "error": "Invalid parameter 'warehouse': String should match pattern '^(?:[a-z]{3}[0-9]|[0-9]{4})$'",
  "request_params": {
    "warehouse": "xyz"
  }
}
Status CodeCauseDescription
400Invalid parameterMalformed warehouse, per_page above 20, or an invalid price range

On numeric store codes popularity_score is null, so the ranking is only meaningful for hubs or postal codes that resolve to a hub.

Code Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import requests

url = "https://mercadona-api.p.rapidapi.com/best-sellers"

params = {
    "postal_code": "46001"
}

headers = {
    "X-RapidAPI-Key": "YOUR_API_KEY",
    "X-RapidAPI-Host": "mercadona-api.p.rapidapi.com"
}

response = requests.get(url, headers=headers, params=params)
data = response.json()["data"]

for item in data["items"]:
    print(f"#{item['rank']} {item['name']}: {item['price_value']} EUR")
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const url = "https://mercadona-api.p.rapidapi.com/best-sellers";

const params = new URLSearchParams({
  postal_code: "46001"
});

const response = await fetch(`${url}?${params}`, {
  headers: {
    "X-RapidAPI-Key": "YOUR_API_KEY",
    "X-RapidAPI-Host": "mercadona-api.p.rapidapi.com"
  }
});

const { data } = await response.json();
data.items.forEach(item => {
  console.log(`#${item.rank} ${item.name}: ${item.price_value} EUR`);
});
1
2
3
4
curl -G "https://mercadona-api.p.rapidapi.com/best-sellers" \
  --data-urlencode "postal_code=46001" \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -H "X-RapidAPI-Host: mercadona-api.p.rapidapi.com"
Start building today

Get your API key and make your first request in under a minute.

Get Your API Key on RapidAPI