GET /category-products

Category Products

List every Mercadona product in a level-1 category or level-2 group, with prices, unit prices and stock for any Spanish postal code, paginated.

Mercadona API

Returns every product of one level-1 category, flattened over its level-2 groups and de-duplicated, with the full price and stock data for the warehouse you ask for. Pass a level-2 id to list only that group. Unlike Search , which stops at the 100 best matches, this endpoint returns the complete listing, and each response includes next_category so you can walk the whole catalog one category at a time. Get the ids from Category Tree .

HTTP Request

GET /category-products

Parameters

ParameterTypeRequiredDefaultDescription
category_idintegerYes-Level-1 category id (e.g. 112). A level-2 id is resolved to its parent and filtered to that group. A level-0 id returns status: false with error.code = level_0_category and error.children[] listing its level-1 ids
warehousestringNovlc1Hub or numeric store code from /warehouses . Assortment and some prices differ per warehouse. Ignored when postal_code is given
postal_codestringNo-Spanish 5-digit postal code, resolved to the warehouse that serves it. Takes precedence over warehouse
pageintegerNo11-indexed page over the flattened, de-duplicated product list
per_pageintegerNo20Items per page, max 20
freshbooleanNofalseBypass the 10-minute cache and fetch fresh data
languageenumNoeses, en or ca. Translates product and category names

Response

Example for category_id=112&postal_code=46001&per_page=2 (arrays trimmed to 2 items):

  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
{
  "status": true,
  "request_id": "d4289404-7617-82ae-a225-a920d0c9",
  "cached_at": "2026-10-14T19:33:40Z",
  "data": {
    "category_id": 112,
    "name": "Aceite, vinagre y sal",
    "order": 7,
    "groups": [
      {
        "category_id": 420,
        "name": "Aceite de oliva",
        "order": 7,
        "items_count": 11
      },
      {
        "category_id": 422,
        "name": "Vinagre y otros aderezos",
        "order": 7,
        "items_count": 8
      }
    ],
    "items": [
      {
        "product_id": "4241",
        "name": "Aceite de oliva 0,4º Hacendado",
        "slug": "aceite-oliva-04o-hacendado-garrafa",
        "url": "https://tienda.mercadona.es/product/4241/aceite-oliva-04o-hacendado-garrafa",
        "thumbnail": "https://prod-mercadona.imgix.net/images/3b8cde7b3cb069ee0316029012cf8562.jpg?fit=crop&h=300&w=300",
        "packaging": "Garrafa",
        "main_feature": null,
        "is_water": false,
        "requires_age_check": false,
        "category": {
          "category_id": 12,
          "name": "Aceite, especias y salsas"
        },
        "group": {
          "category_id": 420,
          "name": "Aceite de oliva"
        },
        "availability": {
          "in_stock": true,
          "status": null,
          "unavailable_from": null,
          "unavailable_weekdays": [],
          "order_limit": 999
        },
        "price": "17.25",
        "price_value": 17.25,
        "previous_price": null,
        "previous_price_value": null,
        "is_price_drop": false,
        "unit_price": "3.450",
        "unit_price_value": 3.45,
        "unit_price_format": "L",
        "bulk_price_value": 3.45,
        "size_format": "l",
        "unit_size": 5.0,
        "is_pack": false,
        "pack_size": null,
        "total_units": null,
        "unit_name": null,
        "iva_percent": 4,
        "approx_size": false,
        "drained_weight": null,
        "currency": "EUR",
        "color_variants": null,
        "warehouse": "vlc1",
        "ean": "8402001027482",
        "brand": "Hacendado",
        "is_new": false
      },
      {
        "product_id": "4240",
        "name": "Aceite de oliva 0,4º Hacendado",
        "slug": "aceite-oliva-04o-hacendado-botella",
        "url": "https://tienda.mercadona.es/product/4240/aceite-oliva-04o-hacendado-botella",
        "thumbnail": "https://prod-mercadona.imgix.net/images/65c2349950feb1958362e06217003b10.jpg?fit=crop&h=300&w=300",
        "packaging": "Botella",
        "main_feature": null,
        "is_water": false,
        "requires_age_check": false,
        "category": {
          "category_id": 12,
          "name": "Aceite, especias y salsas"
        },
        "group": {
          "category_id": 420,
          "name": "Aceite de oliva"
        },
        "availability": {
          "in_stock": true,
          "status": null,
          "unavailable_from": null,
          "unavailable_weekdays": [],
          "order_limit": 999
        },
        "price": "3.70",
        "price_value": 3.7,
        "previous_price": null,
        "previous_price_value": null,
        "is_price_drop": false,
        "unit_price": "3.700",
        "unit_price_value": 3.7,
        "unit_price_format": "L",
        "bulk_price_value": 3.7,
        "size_format": "l",
        "unit_size": 1.0,
        "is_pack": false,
        "pack_size": null,
        "total_units": null,
        "unit_name": null,
        "iva_percent": 4,
        "approx_size": false,
        "drained_weight": null,
        "currency": "EUR",
        "color_variants": null,
        "warehouse": "vlc1",
        "ean": "8402001027475",
        "brand": "Hacendado",
        "is_new": false
      }
    ],
    "total": 35,
    "page": 1,
    "per_page": 2,
    "total_pages": 18,
    "has_next_page": true,
    "next_category": {
      "category_id": 115,
      "name": "Especias"
    },
    "resolved_filters": {
      "warehouse": {
        "input": "46001",
        "resolved": "vlc1",
        "source": "postal_code"
      }
    },
    "language": "es"
  },
  "request_params": {
    "category_id": "112",
    "per_page": "2",
    "postal_code": "46001"
  }
}

Response Fields

Product rows here have the shared product fields plus group and is_new. They do not include category_path or popularity_score; call Product Details if you need more.

FieldTypeDescription
statusbooleantrue when the request succeeded
request_idstringUnique request identifier
cached_atstring | nullISO timestamp when served from cache, null when fetched for this request
dataobjectResponse payload
data.category_idintegerThe level-1 category listed
data.namestringCategory name, translated with language
data.orderintegerDisplay order of the category
data.groups[]arrayLevel-2 groups inside the category
data.groups[].category_idintegerGroup id. Pass it as category_id to list only this group
data.groups[].namestringGroup name
data.groups[].orderintegerDisplay order
data.groups[].items_countintegerProducts in the group
data.items[]arrayProduct rows for this page
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
data.items[].urlstringProduct URL on tienda.mercadona.es
data.items[].thumbnailstringImage URL (imgix)
data.items[].packagingstring | nullPackaging, e.g. "Garrafa" or "Pack-6"
data.items[].main_featurestring | nullHighlighted feature
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
data.items[].groupobjectLevel-2 group the product belongs to inside the category
data.items[].group.category_idintegerLevel-2 group id
data.items[].group.namestringLevel-2 group name
data.items[].availabilityobjectStock and delivery restrictions at the resolved warehouse
data.items[].availability.in_stockbooleanIn stock at the resolved warehouse
data.items[].availability.statusstring | nullRestriction status
data.items[].availability.unavailable_fromstring | nullDate the product stops being available
data.items[].availability.unavailable_weekdaysarrayWeekdays it can’t be delivered
data.items[].availability.order_limitintegerMax units per order (e.g. 999)
data.items[].pricestringDisplay price in EUR, e.g. "3.70"
data.items[].price_valuefloatNumeric price in EUR
data.items[].previous_pricestring | nullPrevious display price, null if the price has not dropped
data.items[].previous_price_valuefloat | nullPrevious numeric price
data.items[].is_price_dropbooleantrue when the current price is below previous_price. Computed from the previous price, not Mercadona’s flag
data.items[].unit_pricestringDisplay unit price, e.g. "3.700"
data.items[].unit_price_valuefloatNumeric unit price
data.items[].unit_price_formatstringUnit of the unit price, e.g. "L" or "kg"
data.items[].bulk_price_valuefloatBulk price
data.items[].size_formatstringSize unit, e.g. "l" or "kg"
data.items[].unit_sizefloatSize in size_format units
data.items[].is_packbooleanPack product
data.items[].pack_sizefloat | nullPack size
data.items[].total_unitsinteger | nullUnits in the pack
data.items[].unit_namestring | nullUnit name, e.g. "briks"
data.items[].iva_percentintegerVAT percentage
data.items[].approx_sizebooleanSize is approximate
data.items[].drained_weightfloat | nullDrained weight
data.items[].currencystringAlways "EUR"
data.items[].color_variantsarray | nullColour variants
data.items[].warehousestringWarehouse that answered
data.items[].eanstringEAN barcode
data.items[].brandstringBrand name as Mercadona writes it
data.items[].is_newbooleanFlagged as new by Mercadona
data.totalintegerProducts in the category (or group)
data.pageintegerCurrent page
data.per_pageintegerItems per page
data.total_pagesintegerTotal pages
data.has_next_pagebooleantrue if there is another page
data.next_categoryobjectNext level-1 category in catalog order, for walking the whole catalog
data.next_category.category_idintegerIts id
data.next_category.namestringIts name
data.resolved_filters.warehouseobjectWarehouse used for this answer
data.resolved_filters.warehouse.inputstring | nullValue you sent (postal_code or warehouse)
data.resolved_filters.warehouse.resolvedstringWarehouse code that answered
data.resolved_filters.warehouse.sourcestringpostal_code, param or default
data.languagestringLanguage used for names
request_paramsobjectQuery parameters you sent, echoed back as strings

Error Responses

A level-0 category id returns HTTP 200 with status: false. error.children[] lists the level-1 categories to call instead (trimmed to 2 items below):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "status": false,
  "request_id": "b732d5c4-ca1a-5687-9d24-30d3c7a3",
  "cached_at": null,
  "error": {
    "code": "level_0_category",
    "message": "Category 12 (Aceite, especias y salsas) is a top-level category with no product listing; call /mercadona/category-products with one of its level-1 ids: [112, 115, 116, 117].",
    "children": [
      {
        "category_id": 112,
        "name": "Aceite, vinagre y sal"
      },
      {
        "category_id": 115,
        "name": "Especias"
      }
    ],
    "warehouse": "vlc1"
  },
  "data": null,
  "request_params": {
    "category_id": "12"
  }
}

The message mentions /mercadona/category-products. That is an internal path: call /category-products.

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

1
2
3
4
5
{
  "status": false,
  "request_id": "...",
  "error": "Invalid parameter 'category_id': Field required"
}
Status CodeCauseDescription
200 (status: false)error.code = level_0_categorycategory_id is a top-level category. Retry with one of the ids in error.children[]
400Missing category_idcategory_id is required
400Invalid warehouseMust be a hub code like vlc1 or a 4-digit store code

Code Examples

The examples page through the whole category with has_next_page.

 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
import requests

url = "https://mercadona-api.p.rapidapi.com/category-products"

params = {
    "category_id": 112,
    "postal_code": "46001",
    "per_page": 20,
    "page": 1
}

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

while True:
    body = requests.get(url, headers=headers, params=params).json()
    if not body["status"]:
        print(f"Error: {body['error']}")
        break

    data = body["data"]
    for item in data["items"]:
        print(f"{item['group']['name']}: {item['name']} {item['price_value']} EUR ({item['unit_price']}/{item['unit_price_format']})")

    if not data["has_next_page"]:
        print(f"Done: {data['total']} products. Next category: {data['next_category']['name']} ({data['next_category']['category_id']})")
        break
    params["page"] += 1
 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
const url = "https://mercadona-api.p.rapidapi.com/category-products";
const headers = {
  "X-RapidAPI-Key": "YOUR_API_KEY",
  "X-RapidAPI-Host": "mercadona-api.p.rapidapi.com"
};

let page = 1;
while (true) {
  const params = new URLSearchParams({
    category_id: "112",
    postal_code: "46001",
    per_page: "20",
    page: String(page)
  });

  const body = await (await fetch(`${url}?${params}`, { headers })).json();
  if (!body.status) {
    console.error(body.error);
    break;
  }

  const { data } = body;
  for (const item of data.items) {
    console.log(`${item.group.name}: ${item.name} ${item.price_value} EUR`);
  }

  if (!data.has_next_page) {
    console.log(`Done: ${data.total} products. Next: ${data.next_category.name}`);
    break;
  }
  page += 1;
}
1
2
3
4
5
6
curl -G "https://mercadona-api.p.rapidapi.com/category-products" \
  --data-urlencode "category_id=112" \
  --data-urlencode "postal_code=46001" \
  --data-urlencode "page=1" \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -H "X-RapidAPI-Host: mercadona-api.p.rapidapi.com"
  • Category Tree : get the level-1 and level-2 ids to pass as category_id
  • Product Details : full product sheet with ingredients, allergens and photos for any product_id
  • Product Search : keyword search inside a category with q and category_id
  • Resolve Warehouse : check which warehouse a postal code maps to
Start building today

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

Get Your API Key on RapidAPI