Skip to content

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

  1. Discover the scope once: GET /v1/coverage lists countries, retailers, and catalog sizes; GET /v1/categories and GET /v1/tags give you the filter vocabulary. All three are free and public.
  2. Search per user query or on a schedule with GET /v1/search - filters in, clean product records out.
  3. Drill into a product with GET /v1/prices/{id} using the id from a hit, to show trend, swings, or the raw observation log.
  4. 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 a near radius search. Free, 0 credits.
  5. Check your balance with GET /v1/me before long batch runs, so a job never dies halfway through a sweep.

Secured endpoints expect your API key in the X-API-Key header:

Terminal window
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.

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.

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.

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:

Terminal window
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.

  • 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: a page_size=100 request costs 50 credits, a page_size=24 request costs 10.
  • Timestamps are RFC 3339 UTC (latest_observed_at, window_resets_at); dates in price ranges are ISO YYYY-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.