Pnp APIpnp.co.za ↗
Access Pick n Pay grocery data: search products, browse categories, get specials, product details, and store locations via 6 structured endpoints.
What is the Pnp API?
The Pick n Pay API exposes 6 endpoints covering product search, category browsing, specials, detailed product data, and store locations from pnp.co.za. The search_products endpoint returns matching products alongside facets for refinement, pagination metadata, and breadcrumbs, while get_product_detail delivers nutritional classifications, stock levels, and full image sets for any individual product code.
curl -X GET 'https://api.parse.bot/scraper/b87810bc-903f-41b8-b38d-c5c911cab324/search_products?page=0&sort=relevance&query=milk&page_size=20' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace pnp-co-za-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
from parse_apis.pick_n_pay_api import PickNPay, Sort, ProductNotFound
pnp = PickNPay()
# Search for products with sorting
for product in pnp.productsummaries.search(query="bread", sort=Sort.PRICE_ASC, limit=5):
print(product.name, product.price.formatted_value, product.stock.stock_level_status)
# Browse a specific category
category = pnp.category("beverages-423144840")
for item in category.products(sort=Sort.PRICE_DESC, limit=3):
print(item.name, item.price.value)
# Get full product details from a summary
for summary in pnp.productsummaries.search(query="milk", limit=1):
detail = summary.details()
print(detail.name, detail.description, detail.available)
for cat in detail.categories:
print(cat.name, cat.code)
# List current specials/promotions
for special in pnp.productsummaries.specials(limit=3):
print(special.name, special.price.formatted_value, special.price.savings)
# List all top-level categories
for cat in pnp.categories.list():
print(cat.category_code, cat.link_name)
# Search for stores
for store in pnp.stores.search(query="cape town", limit=5):
print(store.store_name, store.store_type, store.store_address.city, store.telephone)
Full-text search over Pick n Pay's product catalog. Matches against product names and descriptions. Supports pagination, sorting by relevance or price, and filtering by category, certification, or promotion status. Each product in results carries pricing, stock status, and image URLs. Facets in the response enumerate available refinement dimensions with hit counts.
| Param | Type | Description |
|---|---|---|
| page | integer | Page number (0-based) |
| sort | string | Sort order |
| queryrequired | string | Search keyword (e.g. 'milk', 'bread') |
| filters | string | Additional filter string appended to the search query (e.g. ':isOnPromotion:On+Promotion') |
| page_size | integer | Number of results per page |
{
"type": "object",
"fields": {
"facets": "array of facet objects for filtering (category, certifications, promotion status)",
"products": "array of product summary objects with code, name, price, images, stock, and availability",
"pagination": "object with currentPage, pageSize, sort, totalPages, totalResults",
"breadcrumbs": "array of breadcrumb objects for navigation context",
"currentQuery": "object with query value and URL",
"freeTextSearch": "string echoing the original search term"
},
"sample": {
"data": {
"facets": [
{
"name": "category",
"values": [
{
"name": "Milk, Dairy & Eggs",
"count": 943
}
],
"category": true
}
],
"products": [
{
"code": "000000000000349246_EA",
"name": "PnP UHT Full Cream Milk 1L",
"price": {
"value": 17.99,
"currencyIso": "ZAR",
"formattedValue": "R17.99"
},
"stock": {
"stockLevelStatus": "inStock"
},
"images": [
{
"url": "https://cdn-prd-02.pnp.co.za/sys-master/images/h69/h11/10794954915870/silo-product-image-v2-05Apr2022-180138-6001007041052-Straight_on-19006-4446_400Wx400H",
"format": "product"
}
],
"available": true,
"categoryNames": [
"All Products",
"Beverages",
"Long Life Milk"
]
}
],
"pagination": {
"sort": "relevance",
"pageSize": 72,
"totalPages": 18,
"currentPage": 0,
"totalResults": 1240
},
"breadcrumbs": [],
"currentQuery": {
"query": {
"value": "milk:relevance"
}
},
"freeTextSearch": "milk"
},
"status": "success"
}
}About the Pnp API
Product Search and Discovery
The search_products endpoint accepts a required query string plus optional page, page_size, and sort parameters (relevance, price-asc, price-desc). Results include a products array — each entry carrying code, name, price, images, stock, and available — alongside a facets array that surfaces category, certification, and promotion-status filters. The filters input lets you narrow results further, for example to only on-promotion items, by appending a filter string to the query. get_category_products works identically but takes a category_id (e.g. beverages-423144840) instead of a free-text query, and returns the same product and facet shape with category hierarchy breadcrumbs.
Product Details and Specials
get_product_detail takes a single product_code obtained from search or category results and returns the full record: description, classifications (grouped nutritional and product features), categories array, images with format and alt-text, and a stock object with both stockLevel and stockLevelStatus. The get_specials endpoint lists currently promoted products; each product object includes price with oldPrice and savings details alongside standard stock and image fields. An optional category_id input scopes specials to a single department.
Categories and Store Locations
get_all_categories requires no inputs and returns top-level department navigation as an array of objects with categoryCode, linkName, and url — useful for seeding a category browser or discovering valid category_id values for other endpoints. get_stores accepts an optional query string (name, city, suburb, or street) and returns a stores array with storeId, storeName, storeAddress, storeType, telephone, email, tradingHours, and geolocation coordinates. Omitting the query returns all stores.
The Pnp API is a managed, monitored endpoint for pnp.co.za — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when pnp.co.za changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official pnp.co.za API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a grocery price comparison tool using
search_productswithprice-ascsorting across multiple queries. - Track weekly specials and savings by polling
get_specialsper category and comparingoldPriceagainst currentprice. - Populate a store locator map using
geolocation,tradingHours, andstoreTypefromget_stores. - Extract nutritional
classificationsfromget_product_detailto power a diet-tracking or allergen-screening app. - Index a full product catalog by iterating
get_category_productsacross allcategory_idvalues fromget_all_categories. - Monitor stock availability for specific SKUs by checking
stockLevelStatusinget_product_detailon a schedule. - Scope promotion alerts to a single department by combining
get_specialswith acategory_idfromget_all_categories.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Pick n Pay have an official public developer API?+
How are facets returned from `search_products` and `get_category_products` useful for filtering?+
facets array containing filter dimensions such as sub-category, certifications, and promotion status. You can pass these filter values back via the filters input parameter on the next request to narrow results — for example, appending :isOnPromotion:On+Promotion to show only discounted items within a search or category query.Does the API return product reviews or ratings?+
What are the pagination conventions across endpoints?+
page parameter. The pagination object in each response includes currentPage, pageSize, totalPages, and totalResults, so you can iterate pages programmatically until currentPage reaches totalPages - 1. The get_stores endpoint returns page, totalCount, and totalPages in its pagination object using the same pattern.Does the API cover Click & Collect or delivery slot availability?+
tradingHours and geolocation, and product-level stock data, but fulfilment slots, Click & Collect scheduling, and delivery windows are not included in any endpoint. You can fork the API on Parse and revise it to add endpoints covering those fulfilment details.