Lidl APIlidl.com ↗
Search Lidl US grocery products, browse category trees, and retrieve current prices, promotions, and stock status by store location via 3 REST endpoints.
What is the Lidl API?
The Lidl US API covers 3 endpoints for searching and browsing grocery products across Lidl store locations. The search_products endpoint accepts a keyword and optional store ID to return paginated product results including current price, stock status, promotion details, aisle categories, and a base price text field. Two additional endpoints expose the full category tree and per-category product listings, making it straightforward to build store-aware grocery tools.
curl -X GET 'https://api.parse.bot/scraper/8abf1be8-d321-484a-bcef-d3cf82535ebd/search_products' \ -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 lidl-com-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.
"""
Lidl US Grocery API Client
Search and browse grocery products, prices, and categories at Lidl US stores.
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Optional, Any, Dict, List
from dataclasses import dataclass
@dataclass
class Product:
"""Represents a grocery product from Lidl."""
id: str
name: str
description: str
price: float
currency: str
base_price_text: str
stock_status: str
image_url: str
aisle: int
section: str
promotion: Optional[str] = None
class ParseClient:
"""Client for interacting with the Lidl US Grocery API."""
def __init__(self, api_key: Optional[str] = None):
"""
Initialize the Parse API client.
Args:
api_key: API key for authentication. If not provided, reads from PARSE_API_KEY env var.
"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "8abf1be8-d321-484a-bcef-d3cf82535ebd"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError("API key must be provided or set in PARSE_API_KEY environment variable")
def _call(self, endpoint: str, method: str = "POST", **params) -> Dict[str, Any]:
"""
Make a request to the Parse API.
Args:
endpoint: The API endpoint name (e.g., 'search_products')
method: HTTP method ('GET' or 'POST')
**params: Query or body parameters
Returns:
Response JSON as a dictionary
Raises:
requests.RequestException: If the API request fails
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
if method == "GET":
response = requests.get(url, headers=headers, params=params)
elif method == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
def search_products(
self,
query: str,
store_id: str = "US01053",
limit: int = 20,
offset: int = 0
) -> Dict[str, Any]:
"""
Search for grocery products by keyword at a specific Lidl store.
Args:
query: Search term for products (e.g., 'milk', 'bread', 'chicken')
store_id: Lidl store ID (default: US01053 for Culpeper VA)
limit: Maximum number of results to return per page
offset: Number of results to skip for pagination
Returns:
Dictionary with 'total_results' and 'results' array of products
"""
return self._call(
"search_products",
method="GET",
query=query,
store_id=store_id,
limit=limit,
offset=offset
)
def get_categories(self, store_id: str = "US01053") -> Dict[str, Any]:
"""
List all product categories available at a specific Lidl store.
Args:
store_id: Lidl store ID (default: US01053 for Culpeper VA)
Returns:
Dictionary with 'categories' array containing category objects
"""
return self._call("get_categories", method="GET", store_id=store_id)
def get_category_products(
self,
category_code: str,
store_id: str = "US01053",
limit: int = 20,
offset: int = 0
) -> Dict[str, Any]:
"""
Get all products in a specific category at a Lidl store.
Args:
category_code: Category code from get_categories (e.g., 'OCI2000110')
store_id: Lidl store ID (default: US01053 for Culpeper VA)
limit: Maximum number of results to return per page
offset: Number of results to skip for pagination
Returns:
Dictionary with 'total_results' and 'results' array of products
"""
return self._call(
"get_category_products",
method="GET",
category_code=category_code,
store_id=store_id,
limit=limit,
offset=offset
)
def display_product(product_data: Dict[str, Any]) -> None:
"""Display product information in a readable format."""
product = Product(
id=product_data["id"],
name=product_data["name"],
description=product_data["description"],
price=product_data["price"],
currency=product_data["currency"],
base_price_text=product_data["base_price_text"],
stock_status=product_data["stock_status"],
image_url=product_data["image_url"],
aisle=product_data["aisle"],
section=product_data["section"],
promotion=product_data.get("promotion")
)
status_icon = "✓" if product.stock_status == "INSTOCK" else "✗"
print(f" [{status_icon}] {product.name}")
print(f" Description: {product.description}")
print(f" Price: ${product.price:.2f} ({product.base_price_text})")
print(f" Location: Aisle {product.aisle}, {product.section}")
if product.promotion:
print(f" Promotion: {product.promotion}")
print()
if __name__ == "__main__":
# Initialize the client
client = ParseClient()
print("=" * 60)
print("Lidl US Grocery API - Practical Usage Example")
print("=" * 60)
print()
# Step 1: Get available categories at the store
print("Step 1: Fetching product categories...")
categories_response = client.get_categories(store_id="US01053")
categories = categories_response["categories"]
# Find the dairy category
dairy_category = next((c for c in categories if c["name"] == "dairy"), None)
if dairy_category:
print(f"Found category: {dairy_category['name']} ({dairy_category['code']})")
print(f" Total products in category: {dairy_category['product_count']}")
print()
# Step 2: Search for a specific product
print("Step 2: Searching for 'milk' products...")
search_response = client.search_products(
query="milk",
store_id="US01053",
limit=5
)
print(f"Found {search_response['total_results']} results for 'milk'")
print("Top 5 results:")
print()
# Display search results
for i, product in enumerate(search_response["results"], 1):
print(f"Result {i}:")
display_product(product)
# Step 3: Browse products by category (milk & creamers)
print("Step 3: Browsing 'Milk & Creamers' category...")
milk_category = next((c for c in categories if c.get("name") == "milk & creamers"), None)
if milk_category:
category_response = client.get_category_products(
category_code=milk_category["code"],
store_id="US01053",
limit=3
)
print(f"Category: {milk_category['name']}")
print(f"Total products: {category_response['total_results']}")
print("First 3 products:")
print()
for i, product in enumerate(category_response["results"], 1):
print(f"Product {i}:")
display_product(product)
# Step 4: Find best deals (in-stock items)
print("Step 4: Analyzing in-stock items by price...")
in_stock_products = [
p for p in category_response["results"]
if p["stock_status"] == "INSTOCK"
]
if in_stock_products:
# Sort by price
sorted_products = sorted(in_stock_products, key=lambda x: x["price"])
print(f"In-stock items (sorted by price):")
print()
for i, product in enumerate(sorted_products, 1):
print(f" {i}. {product['name']} - ${product['price']:.2f}")
print(f" ({product['base_price_text']})")
print()
# Calculate average price
avg_price = sum(p["price"] for p in sorted_products) / len(sorted_products)
cheapest = sorted_products[0]
print(f"Average price: ${avg_price:.2f}")
print(f"Cheapest option: {cheapest['name']} at ${cheapest['price']:.2f}")
print()
print("=" * 60)
print("Example completed successfully!")
print("=" * 60)Search for grocery products by keyword at a specific Lidl store. Returns paginated results with prices, stock status, promotions, and aisle/section information.
| Param | Type | Description |
|---|---|---|
| limit | integer | Maximum number of results to return per page. |
| queryrequired | string | Search term for products (e.g. 'milk', 'bread', 'chicken'). |
| offset | integer | Number of results to skip for pagination. |
| store_id | string | Lidl store ID in format US followed by digits (e.g. 'US01053' for Culpeper VA). Determines product availability and pricing. |
{
"type": "object",
"fields": {
"results": "array of product objects with id, name, description, price, currency, base_price_text, stock_status, image_url, categories, promotion, aisle, section",
"total_results": "integer"
},
"sample": {
"results": [
{
"id": "1067979",
"name": "2% reduced fat milk",
"aisle": 1,
"price": 1.88,
"section": "Chiller",
"currency": "USD",
"image_url": "https://production-endpoint.azureedge.net/images/A14KQNQ9DLGMEPA3DTMMIRJ7ADNMURHEE1N6ENPL60O7GD9G60/0a61e8c4-9324-49de-b5ae-cb9da5abc285/PIM_ImageComingSoon.png_500x500.jpg",
"promotion": null,
"categories": [
"OCI1000079",
"OCI2000110"
],
"description": "half gallon",
"stock_status": "INSTOCK",
"base_price_text": "2.94 ¢ per fl.oz."
}
],
"total_results": 288
}
}About the Lidl API
What the API Returns
All three endpoints return product objects sharing a consistent shape: id, name, description, price, currency, base_price_text, stock_status, image_url, categories, and promotion fields. The search_products endpoint accepts a query string (e.g. 'milk', 'chicken') alongside an optional store_id in the format US followed by digits (e.g. US01053 for the Culpeper, VA location). Pagination is controlled with limit and offset parameters, and the response includes a total_results integer so you can implement accurate page counts.
Browsing by Category
The get_categories endpoint returns a hierarchical category tree scoped to a given store, with each category object exposing a code, name, parents array, and product_count. Those code values (e.g. OCI2000110 for milk & creamers, OCI1000079 for dairy) feed directly into get_category_products, which returns the same paginated product listing format as search_products but filtered to a specific department or sub-department.
Store-Level Scoping
The store_id parameter appears on all three endpoints and is what makes results location-specific. Lidl's US inventory, promotions, and stock status can vary by store, so passing a store_id ensures the price and availability data matches what a shopper would actually see at that location. Omitting it returns a default catalog view. The base_price_text field in product responses often conveys unit pricing (e.g. per lb or per oz), which is useful for unit-price comparison logic.
The Lidl API is a managed, monitored endpoint for lidl.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when lidl.com 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 lidl.com 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 tracker that monitors Lidl product prices and promotion changes by store over time.
- Populate a meal planning app with current in-stock Lidl products filtered by category using get_category_products.
- Compare Lidl shelf prices against other retailers using the price and base_price_text fields from search_products.
- Create a store-specific shopping list tool that validates stock_status before surfacing items to users.
- Index Lidl's full product catalog by walking the category tree from get_categories and paginating through each category.
- Alert shoppers when a searched product has an active promotion by monitoring the promotions field in search_products results.
- Build a dietary filter layer on top of category browsing by combining category codes with product name and description fields.
| 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.