Skip to content

REST API

Every MealCP capability is a plain HTTPS GET that returns JSON - there are no SDKs to install, webhooks to receive, or request bodies to sign. Point any HTTP client at https://api.mealcp.com, send your API key in a header, and read the response. This page covers the conventions shared by all endpoints: authentication, the error envelope, pagination, and credit costs. The endpoint-specific pages (search, prices, taxonomy) document inputs and outputs in full.

Base URL: https://api.mealcp.com

  1. Discover the scope once: GET /v1/coverage lists countries, retailers, and catalogue 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, normalized product records out.
  3. Drill into a product with GET /v1/prices/{id} using the id from a hit, to show trend, volatility, or the raw observation log.
  4. Check your balance with GET /v1/me before long batch runs, so a job never dies halfway through a sweep.

Authenticated 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, 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 extracted, 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/{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/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 semantics are listed 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 are charged per request, not per result: sweeping 10 pages of results costs 10 credits regardless of page size. If a batch needs the full result set, use the largest page_size (100 on search) to minimize the request count, and prefer narrower filters over long walks - a query scoped with country or category usually needs far fewer pages.

  • All responses are JSON, including errors.
  • All endpoints are read-only GETs, so failed calls are always safe to retry exactly as issued.
  • Query parameters do not change the cost - a page_size=100 search costs the same 1 credit as page_size=1.
  • 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.