# Pingo Doce API — Portuguese supermarket prices: shelf price, promotion and was price, PVPR, price per kg/litre, promotion end date, ingredients, allergens and nutrition from pingodoce.pt

> Search Pingo Doce's online shop: shelf price, was price of a promotion, recommended retail price (PVPR), promotion badge and end date, price per kg/l, pack size, brand, category. `query` required; filters: category, brand, diet, min_price, max_price; sort; paging up to 100 per page; optional post code for that delivery area's range.
> ReefAPI engine `pingodoce` · 6 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/pingodoce/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed calls are free except verified SHEIN NOT_FOUND on product/detail and price (4 credits).
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http). Clients that add connectors by URL, such as ChatGPT and the Claude app, connect with OAuth 2.1 (the user pastes their key once on a ReefAPI page; discovery at `/.well-known/oauth-protected-resource/mcp`). Config files send the key as `Authorization: Bearer <key>`. `?key=<key>` in the URL also works as a last-resort fallback.

## Endpoints

### POST https://api.reefapi.com/pingodoce/v1/search — 3 credits
Search Pingo Doce's online shop: shelf price, was price of a promotion, recommended retail price (PVPR), promotion badge and end date, price per kg/l, pack size, brand, category. `query` required; filters: category, brand, diet, min_price, max_price; sort; paging up to 100 per page; optional post code for that delivery area's range.

**Parameters:**
- `query` (string, required) — Search words as typed in the Pingo Doce shop (Portuguese works best).
- `category` (string, optional) — Pingo Doce category id as `categories` returns it (e.g. ec_leitebebidasvegetais_900). An id the site does not know is rejected.
- `brand` (string, optional) — Exact brand name as the shop prints it (e.g. Mimosa, Pingo Doce, Alpro).
- `diet` (enum, optional) — One of the shop's own food-choice facets: organic, vegan, gluten_free, lactose_free, milk_free, no_added_sugar, light, low_fat, high_protein, source_of_protein, source_of_fibre, source_of_omega3. [one of: organic, vegan, gluten_free, lactose_free, milk_free, no_added_sugar, light, low_fat, high_protein, source_of_protein, source_of_fibre, source_of_omega3]
- `min_price` (number, optional) — Minimum shelf price in EUR (the number in `price`, per its `price_unit`).
- `max_price` (number, optional) — Maximum shelf price in EUR.
- `sort` (enum, optional, default "relevance") — relevance · price_asc · price_desc · name_asc · name_desc. [one of: relevance, price_asc, price_desc, name_asc, name_desc]
- `page` (integer, optional, default 1) — Result page, 1-based.
- `per_page` (integer, optional, default 48) — Products per page, 1-100 (default 48).
- `postal_code` (string, optional) — Portuguese post code (NNNN-NNN) of a home-delivery area. Pingo Doce's range depends on it (measured: 'leite' 255 rows with no area, 155 Lisboa 1000-001, 200 Porto 4000-322); prices were the same across areas. Omit for the site's default range; the response's `store` says which.

**Returns:** store{postal_code, delivery_type, store_name, store_defaulted, resolved_from}, query, category, filters, sort, total, total_is_exact, page, per_page, has_more, returned, results[]{rank, product_id (-> product.product_id), name, brand, price, price_unit (un|kg|…: what `price` is per), price_text, regular_price (struck-through price of a promotion), recommended_retail_price (manufacturer PVPR), currency, on_offer, promotion_label, promotion_code, promotion_end{text, day, month, year}, pack_size, unit_price, unit_price_unit, unit_info_text, category, category_path, analytics_price, image, url}

**Example request body:**
```json
{
  "query": "leite"
}
```

### POST https://api.reefapi.com/pingodoce/v1/category — 3 credits
List one Pingo Doce category (id from `categories`) with the same row fields, filters and paging as `search` — the way to walk the whole catalogue.

**Parameters:**
- `category` (string, optional) — Pingo Doce category id as `categories` returns it (e.g. ec_leitebebidasvegetais_900). An id the site does not know is rejected.
- `brand` (string, optional) — Exact brand name as the shop prints it (e.g. Mimosa, Pingo Doce, Alpro).
- `diet` (enum, optional) — One of the shop's own food-choice facets: organic, vegan, gluten_free, lactose_free, milk_free, no_added_sugar, light, low_fat, high_protein, source_of_protein, source_of_fibre, source_of_omega3. [one of: organic, vegan, gluten_free, lactose_free, milk_free, no_added_sugar, light, low_fat, high_protein, source_of_protein, source_of_fibre, source_of_omega3]
- `min_price` (number, optional) — Minimum shelf price in EUR (the number in `price`, per its `price_unit`).
- `max_price` (number, optional) — Maximum shelf price in EUR.
- `sort` (enum, optional, default "relevance") — relevance · price_asc · price_desc · name_asc · name_desc. [one of: relevance, price_asc, price_desc, name_asc, name_desc]
- `page` (integer, optional, default 1) — Result page, 1-based.
- `per_page` (integer, optional, default 48) — Products per page, 1-100 (default 48).
- `postal_code` (string, optional) — Portuguese post code (NNNN-NNN) of a home-delivery area. Pingo Doce's range depends on it (measured: 'leite' 255 rows with no area, 155 Lisboa 1000-001, 200 Porto 4000-322); prices were the same across areas. Omit for the site's default range; the response's `store` says which.

**Returns:** store{postal_code, delivery_type, store_name, store_defaulted, resolved_from}, query, category, filters, sort, total, total_is_exact, page, per_page, has_more, returned, results[]{rank, product_id (-> product.product_id), name, brand, price, price_unit (un|kg|…: what `price` is per), price_text, regular_price (struck-through price of a promotion), recommended_retail_price (manufacturer PVPR), currency, on_offer, promotion_label, promotion_code, promotion_end{text, day, month, year}, pack_size, unit_price, unit_price_unit, unit_info_text, category, category_path, analytics_price, image, url}

**Example request body:**
```json
{
  "category": "ec_leitebebidasvegetais_900"
}
```

### POST https://api.reefapi.com/pingodoce/v1/promotions — 3 credits
Pingo Doce products on promotion right now (the shop's Promoções section): offer price, was price or PVPR, badge, end date. Narrow with `query`, `brand`, `diet`, price range.

**Parameters:**
- `query` (string, optional) — Optional search words inside the promotions.
- `brand` (string, optional) — Exact brand name as the shop prints it (e.g. Mimosa, Pingo Doce, Alpro).
- `diet` (enum, optional) — One of the shop's own food-choice facets: organic, vegan, gluten_free, lactose_free, milk_free, no_added_sugar, light, low_fat, high_protein, source_of_protein, source_of_fibre, source_of_omega3. [one of: organic, vegan, gluten_free, lactose_free, milk_free, no_added_sugar, light, low_fat, high_protein, source_of_protein, source_of_fibre, source_of_omega3]
- `min_price` (number, optional) — Minimum shelf price in EUR (the number in `price`, per its `price_unit`).
- `max_price` (number, optional) — Maximum shelf price in EUR.
- `sort` (enum, optional, default "relevance") — relevance · price_asc · price_desc · name_asc · name_desc. [one of: relevance, price_asc, price_desc, name_asc, name_desc]
- `page` (integer, optional, default 1) — Result page, 1-based.
- `per_page` (integer, optional, default 48) — Products per page, 1-100 (default 48).
- `postal_code` (string, optional) — Portuguese post code (NNNN-NNN) of a home-delivery area. Pingo Doce's range depends on it (measured: 'leite' 255 rows with no area, 155 Lisboa 1000-001, 200 Porto 4000-322); prices were the same across areas. Omit for the site's default range; the response's `store` says which.

**Returns:** store{postal_code, delivery_type, store_name, store_defaulted, resolved_from}, query, category, filters, sort, total, total_is_exact, page, per_page, has_more, returned, results[]{rank, product_id (-> product.product_id), name, brand, price, price_unit (un|kg|…: what `price` is per), price_text, regular_price (struck-through price of a promotion), recommended_retail_price (manufacturer PVPR), currency, on_offer, promotion_label, promotion_code, promotion_end{text, day, month, year}, pack_size, unit_price, unit_price_unit, unit_info_text, category, category_path, analytics_price, image, url}

**Example request body:**
```json
{
  "query": "leite"
}
```

### POST https://api.reefapi.com/pingodoce/v1/product — 3 credits
One Pingo Doce product by the `product_id` a search row returns: price, was price or PVPR, promotion badge and end date, price per kg/l, availability and order limits, category, images, and the label: regulated name, ingredients, allergens, nutrition table, vitamins and minerals, origin, storage, preparation, producer.

**Parameters:**
- `product_id` (string, required) — The numeric product id a search row returns, or its https://www.pingodoce.pt/home/produtos/…-<id>.html URL.

**Returns:** product{product_id, name, brand, short_description, description, price, price_unit, price_text, regular_price, recommended_retail_price, currency, on_offer, promotion_label, promotion_code, promotion_end, pack_size, unit_price, unit_price_unit, unit_info_text, sales_unit, available, online, ready_to_order, availability_messages[], min_order_quantity, max_order_quantity, rating, category, category_path, product_family, national_product, origin_label, returnable_package, returnable_package_price, images[], url}, label{regulated_name, ingredients, ingredients_placeholder, allergens, origin, preparation, storage, storage_after_opening, conservation[], food_choices[], producer, producer_address, responsible, nutrition_per, nutrition[]{nutrient, code, amount, amount_text, unit}, vitamins_and_minerals[], aminogram[]}

**Example request body:**
```json
{
  "product_id": "41043"
}
```

### POST https://api.reefapi.com/pingodoce/v1/categories — 3 credits
Pingo Doce's category tree from the shop menu: id, name, URL, children. Ids feed `category` and the `category` filter.

**Parameters:**
- `category` (string, optional) — Return only this category's subtree; omit for the whole tree.

**Returns:** parent, total_categories, categories[]{category_id, name, url, path, depth, children[]}

**Example request body:**
```json
{
  "category": "ec_leitebebidasvegetais_900"
}
```

### POST https://api.reefapi.com/pingodoce/v1/store — 1 credit
Whether Pingo Doce delivers to a Portuguese post code (home delivery) or only offers store pickup there — the area `postal_code` selects in the listing actions.

**Parameters:**
- `postal_code` (string, required) — Portuguese post code (NNNN-NNN).

**Returns:** postal_code, home_delivery, delivery_type, provider, message

**Example request body:**
```json
{
  "postal_code": "1000-001"
}
```

## At scale
- **Volume:** 5M+ requests a day, measured at 60 requests a second across the fleet with no
  central bottleneck. Per-key limits are raised for high-volume accounts; volume pricing on request.
- **Missing a source:** tell us a site we do not cover and it becomes an engine. A customer asked
  for bestprice.gr on 21 Sep 2026 and it was in the catalog on 22 Sep.
- **Support:** 2 minute median time from a question in the live chat to the first answer. Setup
  help included, no support tier to buy.
- **One key, one credit pool** across every API. No per-site plans, no separate subscriptions.

## More
- Try it live, no code: https://reefapi.com/playground?engine=pingodoce
- Human docs page: https://reefapi.com/docs/pingodoce
- Overview page: https://reefapi.com/pingodoce-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
