# FairPrice API — Singapore supermarket prices from fairprice.com.sg: price paid and regular price, discount, multi-buy deals, deposit, price per kg/l, stock, barcodes, ingredients and nutrition

> Search NTUC FairPrice's online shop (Singapore): price paid and regular price, discount S$ and %, multi-buy deal, spend-and-save and gift promotions, container deposit, pack size and price per kg/l/pc, stock level, brand, barcodes, origin, dietary labels, rating. `query` required; filters brand, diet, origin, promo_type, min_price/max_price (FairPrice's price bands); sort; page; optional postal_code or store_id for that store's range and stock.
> ReefAPI engine `fairprice` · 6 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/fairprice/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). Send the key as `Authorization: Bearer <key>`, or put it in the URL (`?key=<key>`) when the client has no header field, as ChatGPT does.

## Endpoints

### POST https://api.reefapi.com/fairprice/v1/search — 2 credits
Search NTUC FairPrice's online shop (Singapore): price paid and regular price, discount S$ and %, multi-buy deal, spend-and-save and gift promotions, container deposit, pack size and price per kg/l/pc, stock level, brand, barcodes, origin, dietary labels, rating. `query` required; filters brand, diet, origin, promo_type, min_price/max_price (FairPrice's price bands); sort; page; optional postal_code or store_id for that store's range and stock.

**Parameters:**
- `query` (string, required) — Search words as typed on fairprice.com.sg (English). A barcode or the FairPrice SKU also works.
- `brand` (string, optional) — Brand as its slug (a row's `brand_slug`, e.g. marigold, nestle-nan) or its printed name (Marigold).
- `diet` (enum, optional) — One dietary attribute (the site's own facet): halal, healthier_choice, organic, vegetarian, gluten_free, lactose_free, trans_fat_free, hypoallergenic. [one of: halal, healthier_choice, organic, vegetarian, gluten_free, lactose_free, trans_fat_free, hypoallergenic]
- `origin` (string, optional) — Country/place of origin as the site prints it (e.g. Japan, Malaysia, New Zealand).
- `promo_type` (enum, optional) — Only products in one FairPrice promotion programme: everyday_low_price, mix_and_match, price_slash (lowest price in 30 days), carton_and_bundle, promotions_boost, flash_sale, fresh_picks, free_gift, pwp. [one of: everyday_low_price, mix_and_match, price_slash, carton_and_bundle, promotions_boost, flash_sale, fresh_picks, free_gift, pwp]
- `min_price` (number, optional) — Lower bound of the REGULAR price in SGD. FairPrice only filters by its own price bands, so this must be one of 0, 3, 5, 10, 25 (any other value is rejected, not rounded).
- `max_price` (number, optional) — Upper bound of the REGULAR price in SGD: one of 3, 5, 10, 25. The band is applied to the regular price (`regular_price`, or `price` when there is no cut), so a discounted item whose regular price is above the bound is not returned.
- `sort` (enum, optional, default "relevance") — relevance · price_asc · price_desc (by regular price) · brand_asc · brand_desc. [one of: relevance, price_asc, price_desc, brand_asc, brand_desc]
- `page` (integer, optional, default 1) — Result page, 1-50. Pages hold 20 products (fixed by the source); the source stops at page 50, so a listing shows at most 1,000 products.
- `postal_code` (string, optional) — Singapore postal code (6 digits). FairPrice serves each address from one store and the range, stock and some discounts follow that store (measured: 'milk' 1,445 products at the default store, 1,244 at Sun Plaza, 719 at Bedok Mall). Omit for the site's default store. Costs one extra small lookup.
- `store_id` (integer, optional) — FairPrice store id as the `store` action returns it (e.g. 45). Takes precedence over postal_code.

**Returns:** store{store_id, store_name, resolved_from}, query, category, filters, sort, total, page, page_size, last_page, has_more, returned, facets{brand[], Dietary Attributes[], Country/Place Of Origin[], price[], tag[]}, results[]{rank, product_id (-> product.product_id), sku, slug, name, brand, brand_slug, barcodes[], price (what a shopper pays), regular_price (price before the cut, null when no cut), discount_amount, discount_percent, currency (SGD), on_offer, price_cut_valid_to, multibuy{text, quantity, total_price, price_each, mix_and_match, any_of_product_ids[], valid_from, valid_to}, promotions[]{offer_id, type, kind (spend_and_save|spend_get_gift|buy_get_gift|other), text, short_text, quantity, total, total_type, min_spend, valid_from, valid_to}, pack_size, unit_price (price per kg / l / pc computed from pack_size), unit_price_unit, source_unit_price_text, sold_by_weight, deposit{amount, text}, in_stock, stock_level, online_stock, sponsored, rating, review_count, category{id, name, slug}, category_path[], origin, dietary[], nutrigrade, supplier, marketplace_seller, store{store_id, store_name}, image, url}

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

### POST https://api.reefapi.com/fairprice/v1/category — 2 credits
List one FairPrice category (slug from `categories`, e.g. fresh-milk) with the same row fields, filters and sorts as `search`.

**Parameters:**
- `category` (string, required) — Category slug as `categories` returns it (e.g. fresh-milk, dairy-chilled-eggs) or a fairprice.com.sg/category/<slug> URL.
- `brand` (string, optional) — Brand as its slug (a row's `brand_slug`, e.g. marigold, nestle-nan) or its printed name (Marigold).
- `diet` (enum, optional) — One dietary attribute (the site's own facet): halal, healthier_choice, organic, vegetarian, gluten_free, lactose_free, trans_fat_free, hypoallergenic. [one of: halal, healthier_choice, organic, vegetarian, gluten_free, lactose_free, trans_fat_free, hypoallergenic]
- `origin` (string, optional) — Country/place of origin as the site prints it (e.g. Japan, Malaysia, New Zealand).
- `promo_type` (enum, optional) — Only products in one FairPrice promotion programme: everyday_low_price, mix_and_match, price_slash (lowest price in 30 days), carton_and_bundle, promotions_boost, flash_sale, fresh_picks, free_gift, pwp. [one of: everyday_low_price, mix_and_match, price_slash, carton_and_bundle, promotions_boost, flash_sale, fresh_picks, free_gift, pwp]
- `min_price` (number, optional) — Lower bound of the REGULAR price in SGD. FairPrice only filters by its own price bands, so this must be one of 0, 3, 5, 10, 25 (any other value is rejected, not rounded).
- `max_price` (number, optional) — Upper bound of the REGULAR price in SGD: one of 3, 5, 10, 25. The band is applied to the regular price (`regular_price`, or `price` when there is no cut), so a discounted item whose regular price is above the bound is not returned.
- `sort` (enum, optional, default "relevance") — relevance · price_asc · price_desc (by regular price) · brand_asc · brand_desc. [one of: relevance, price_asc, price_desc, brand_asc, brand_desc]
- `page` (integer, optional, default 1) — Result page, 1-50. Pages hold 20 products (fixed by the source); the source stops at page 50, so a listing shows at most 1,000 products.
- `postal_code` (string, optional) — Singapore postal code (6 digits). FairPrice serves each address from one store and the range, stock and some discounts follow that store (measured: 'milk' 1,445 products at the default store, 1,244 at Sun Plaza, 719 at Bedok Mall). Omit for the site's default store. Costs one extra small lookup.
- `store_id` (integer, optional) — FairPrice store id as the `store` action returns it (e.g. 45). Takes precedence over postal_code.

**Returns:** store{store_id, store_name, resolved_from}, query, category, filters, sort, total, page, page_size, last_page, has_more, returned, facets{brand[], Dietary Attributes[], Country/Place Of Origin[], price[], tag[]}, results[]{rank, product_id (-> product.product_id), sku, slug, name, brand, brand_slug, barcodes[], price (what a shopper pays), regular_price (price before the cut, null when no cut), discount_amount, discount_percent, currency (SGD), on_offer, price_cut_valid_to, multibuy{text, quantity, total_price, price_each, mix_and_match, any_of_product_ids[], valid_from, valid_to}, promotions[]{offer_id, type, kind (spend_and_save|spend_get_gift|buy_get_gift|other), text, short_text, quantity, total, total_type, min_spend, valid_from, valid_to}, pack_size, unit_price (price per kg / l / pc computed from pack_size), unit_price_unit, source_unit_price_text, sold_by_weight, deposit{amount, text}, in_stock, stock_level, online_stock, sponsored, rating, review_count, category{id, name, slug}, category_path[], origin, dietary[], nutrigrade, supplier, marketplace_seller, store{store_id, store_name}, image, url}

**Example request body:**
```json
{
  "category": "fresh-milk"
}
```

### POST https://api.reefapi.com/fairprice/v1/promotions — 2 credits
Everything FairPrice has on promotion right now (the site's promotions page, 28,563 products on 2026-10-15): price paid, regular price, discount, multi-buy and gift deals. Narrow with brand, diet, origin, promo_type, price bands. For promotions matching words, use `search` with `promo_type`.

**Parameters:**
- `brand` (string, optional) — Brand as its slug (a row's `brand_slug`, e.g. marigold, nestle-nan) or its printed name (Marigold).
- `diet` (enum, optional) — One dietary attribute (the site's own facet): halal, healthier_choice, organic, vegetarian, gluten_free, lactose_free, trans_fat_free, hypoallergenic. [one of: halal, healthier_choice, organic, vegetarian, gluten_free, lactose_free, trans_fat_free, hypoallergenic]
- `origin` (string, optional) — Country/place of origin as the site prints it (e.g. Japan, Malaysia, New Zealand).
- `promo_type` (enum, optional) — Only products in one FairPrice promotion programme: everyday_low_price, mix_and_match, price_slash (lowest price in 30 days), carton_and_bundle, promotions_boost, flash_sale, fresh_picks, free_gift, pwp. [one of: everyday_low_price, mix_and_match, price_slash, carton_and_bundle, promotions_boost, flash_sale, fresh_picks, free_gift, pwp]
- `min_price` (number, optional) — Lower bound of the REGULAR price in SGD. FairPrice only filters by its own price bands, so this must be one of 0, 3, 5, 10, 25 (any other value is rejected, not rounded).
- `max_price` (number, optional) — Upper bound of the REGULAR price in SGD: one of 3, 5, 10, 25. The band is applied to the regular price (`regular_price`, or `price` when there is no cut), so a discounted item whose regular price is above the bound is not returned.
- `sort` (enum, optional, default "relevance") — relevance · price_asc · price_desc (by regular price) · brand_asc · brand_desc. [one of: relevance, price_asc, price_desc, brand_asc, brand_desc]
- `page` (integer, optional, default 1) — Result page, 1-50. Pages hold 20 products (fixed by the source); the source stops at page 50, so a listing shows at most 1,000 products.
- `postal_code` (string, optional) — Singapore postal code (6 digits). FairPrice serves each address from one store and the range, stock and some discounts follow that store (measured: 'milk' 1,445 products at the default store, 1,244 at Sun Plaza, 719 at Bedok Mall). Omit for the site's default store. Costs one extra small lookup.
- `store_id` (integer, optional) — FairPrice store id as the `store` action returns it (e.g. 45). Takes precedence over postal_code.

**Returns:** store{store_id, store_name, resolved_from}, query, category, filters, sort, total, page, page_size, last_page, has_more, returned, facets{brand[], Dietary Attributes[], Country/Place Of Origin[], price[], tag[]}, results[]{rank, product_id (-> product.product_id), sku, slug, name, brand, brand_slug, barcodes[], price (what a shopper pays), regular_price (price before the cut, null when no cut), discount_amount, discount_percent, currency (SGD), on_offer, price_cut_valid_to, multibuy{text, quantity, total_price, price_each, mix_and_match, any_of_product_ids[], valid_from, valid_to}, promotions[]{offer_id, type, kind (spend_and_save|spend_get_gift|buy_get_gift|other), text, short_text, quantity, total, total_type, min_spend, valid_from, valid_to}, pack_size, unit_price (price per kg / l / pc computed from pack_size), unit_price_unit, source_unit_price_text, sold_by_weight, deposit{amount, text}, in_stock, stock_level, online_stock, sponsored, rating, review_count, category{id, name, slug}, category_path[], origin, dietary[], nutrigrade, supplier, marketplace_seller, store{store_id, store_name}, image, url}

**Example request body:**
```json
{
  "brand": "marigold"
}
```

### POST https://api.reefapi.com/fairprice/v1/product — 1 credit
One FairPrice product by the `product_id` a search row returns (or its slug / URL): prices, discount with its end date, multi-buy and other promotions, deposit, stock at the store, barcodes, category path, images, and the label: key information, ingredients, storage, preparation, Nutri-Grade, nutrition table, product details.

**Parameters:**
- `product_id` (string, required) — The `product_id` a search row returns (e.g. 1623656), or the row's `slug`, or a fairprice.com.sg/product/<slug> URL.
- `postal_code` (string, optional) — Singapore postal code (6 digits). FairPrice serves each address from one store and the range, stock and some discounts follow that store (measured: 'milk' 1,445 products at the default store, 1,244 at Sun Plaza, 719 at Bedok Mall). Omit for the site's default store. Costs one extra small lookup.
- `store_id` (integer, optional) — FairPrice store id as the `store` action returns it (e.g. 45). Takes precedence over postal_code.

**Returns:** product{product_id, sku, slug, name, brand, brand_slug, barcodes[], price, regular_price, discount_amount, discount_percent, currency, on_offer, price_cut_valid_to, multibuy{...}, promotions[]{...}, pack_size, unit_price, unit_price_unit, source_unit_price_text, sold_by_weight, deposit, in_stock, stock_level, online_stock, sponsored, rating, review_count, category, category_path[], origin, dietary[], nutrigrade, supplier, marketplace_seller, store, image, url, images[], description, key_information, ingredients, storage, preparation, pack_type, product_type, nutrition{columns[], rows[]{nutrient, values[]}}, linkpoint_eligible, details[]{label, value}, tags[], secondary_category_ids[]}, store

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

### POST https://api.reefapi.com/fairprice/v1/categories — 2 credits
FairPrice's category tree from the shop menu (1,004 nodes on 2026-10-15): slug, id, name, URL, children. Slugs feed `category`.

**Parameters:**
- `category` (string, optional) — Return only this category's subtree; omit for the whole tree.
- `postal_code` (string, optional) — Singapore postal code (6 digits). FairPrice serves each address from one store and the range, stock and some discounts follow that store (measured: 'milk' 1,445 products at the default store, 1,244 at Sun Plaza, 719 at Bedok Mall). Omit for the site's default store. Costs one extra small lookup.
- `store_id` (integer, optional) — FairPrice store id as the `store` action returns it (e.g. 45). Takes precedence over postal_code.

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

**Example request body:**
```json
{
  "category": "dairy-chilled-eggs"
}
```

### POST https://api.reefapi.com/fairprice/v1/store — 1 credit
Which FairPrice store delivers to a Singapore postal code (the store whose range and stock the listings show when you pass the same `postal_code`, or its `store_id`).

**Parameters:**
- `postal_code` (string, required) — Singapore postal code, 6 digits.

**Returns:** postal_code, store_id, store_name, store_address, store_code, zone_id, delivery_fee, available_stores[]{store_id, store_name}

**Example request body:**
```json
{
  "postal_code": "529510"
}
```

## 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=fairprice
- Human docs page: https://reefapi.com/docs/fairprice
- Overview page: https://reefapi.com/fairprice-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
