MealCP Food Prices API Guide
MealCP is a grocery price API and supermarket API for food prices. It uses
plain HTTPS GET, returns JSON, and needs no SDKs, webhooks, or signed
bodies. Point your client at https://api.mealcp.com, send your API key in
the X-API-Key header, and read the response. This guide covers the shared
rules for all endpoints: auth, the error envelope, paging, and credit cost.
The endpoint pages for search,
products, prices,
stores, and taxonomy cover inputs and
outputs.
Base URL: https://api.mealcp.com
A typical integration
Section titled “A typical integration”- Discover the scope once:
GET /v1/coveragelists countries, retailers, and catalog sizes;GET /v1/categoriesandGET /v1/tagsgive you the filter vocabulary. All three are free and public. - Search per user query or on a schedule with
GET /v1/search- filters in, clean product records out. - Drill into a product with
GET /v1/prices/{id}using theidfrom a hit, to show trend, swings, or the raw observation log. - Place it in the real world with
GET /v1/stores- filter the physical-store directory by retailer or country, or find the nearest supermarkets with anearradius search. Free, 0 credits. - Check your balance with
GET /v1/mebefore long batch runs, so a job never dies halfway through a sweep.
Authentication
Section titled “Authentication”Secured endpoints expect your API key in the X-API-Key header:
curl -H "X-API-Key: $MEALCP_API_KEY" \ "https://api.mealcp.com/v1/search?q=hapanjuurileip%C3%A4&country=FI"Missing or invalid keys get a 401:
{ "error": { "code": "unauthorized", "message": "missing X-API-Key header" }}The key travels on every call to the search, product, price, stores, and me
endpoints; the taxonomy and coverage endpoints are public and need none.
Treat the key as a server-side secret - anything shipped to a browser or a
mobile bundle can be read, so proxy requests through your backend
instead. Check your key and live credit balance any time with
GET /v1/me.
Endpoints
Section titled “Endpoints”| Endpoint | Auth | Description |
|---|---|---|
GET /v1/search |
key | Keyword search with faceted filtering |
GET /v1/products |
key | Cursor-paginated full-catalogue enumeration |
GET /v1/products/{id} |
key | One product by id |
GET /v1/prices/{id} |
key | Aggregated price-history stats |
GET /v1/prices/{id}/observations |
key | Raw price observations |
GET /v1/stores |
key | Physical store locations with near-me search |
GET /v1/categories |
- | Category tree (flat rows) |
GET /v1/tags |
- | Canonical tag vocabulary |
GET /v1/me |
key | Your identity, cap, and credit balance |
GET /v1/coverage |
- | Per-country catalogue coverage |
Product ids are opaque (rp_ + 32 hex chars). Take them verbatim from a
search hit - never construct them yourself.
Error handling
Section titled “Error handling”Every non-2xx response uses the same envelope, so one error handler covers the whole API. Match on the HTTP status:
| Status | Meaning | Client action |
|---|---|---|
401 |
Missing/invalid key | Check the X-API-Key header; rotate if lost |
402 |
Credits exhausted | Wait for the window reset or request a higher cap |
422 |
Invalid params | Fix each field named in error.details[] |
429 |
Rate limit exceeded | Honor the Retry-After header (seconds) |
Two further cases: search can answer 503 while the search service restarts
(retry with backoff), and 400 flags semantically impossible parameters such
as a min_price above max_price. A handler that logs the status, reads
error.message, and retries only on 429/503 is enough for production.
The full rules are in Credits & limits.
Pagination
Section titled “Pagination”List endpoints paginate with page (1-based) and page_size. The response
carries found - the total match count - so walk pages by incrementing
page until page * page_size >= found:
curl -H "X-API-Key: $MEALCP_API_KEY" \ "https://api.mealcp.com/v1/search?q=oat%20milk&page=2&page_size=100"Credits scale with the data a request can return: a search page costs a flat
10 credits up to 24 rows, then 0.5 credits per requested row, so sweeping
with default pages costs 10 credits per page. If a batch needs the full
result set, prefer narrower filters over long walks - a query scoped with
country or category usually needs far fewer pages. For durable
full-catalogue syncs,
GET /v1/products paginates with an opaque cursor
instead of page numbers, so a walk sees no duplicates or gaps even as the
catalogue changes mid-run.
Conventions
Section titled “Conventions”- All responses are JSON, including errors.
- All endpoints are read-only
GETs, so failed calls are safe to retry exactly as issued. - Search cost scales with
page_size: apage_size=100request costs 50 credits, apage_size=24request costs 10. - Timestamps are RFC 3339 UTC (
latest_observed_at,window_resets_at); dates in price ranges are ISOYYYY-MM-DD. - Full machine-readable spec:
https://api.mealcp.com/openapi.json- generate a typed client from it instead of hand-writing request types.
Which endpoints need an API key, and which are public?
Search, product, price, store, and account endpoints need the API key in the
X-API-Key header. The taxonomy and coverage endpoints are public, so
GET /v1/coverage, GET /v1/categories,
and GET /v1/tags work without auth.
How should API keys be handled in a client app?
Treat the API key as a server-side secret. Do not ship it in browser code or
mobile apps, because it can be read. Route client requests through your
backend and have the backend call MealCP with X-API-Key.
When should a request be retried?
All endpoints are read-only GETs, so failed calls are safe to retry, but
retry selectively: retry on 429, honoring Retry-After, and on 503 with
backoff. Log and fix other errors, like 401 auth failures or 400
logically invalid parameters, instead of retrying them as-is.
How can batch jobs reduce credit use?
Credits scale with the data a request can return: search is a flat 10
credits for the default 24-row page and 0.5 credits per requested row above
that, the products list is 50 per 100-row page. Narrow filters like
country or category reduce the pages you need; on search, walking with
the default page size is the cheapest way to sweep a large result set.
Can product ids be generated or inferred from product data?
No. Product ids are opaque values in the form rp_ plus 32 hex chars. Copy
them from search results and pass them verbatim to the
product or price endpoints.