KcalbaseQuickstartKeys and quotasAPI referenceAttributionErrorsChangelogTerms

Kcalbase API quickstart

UK-first food and nutrition data, one canonical row, gram weights on every serving, provenance and licence on every row. Read-only, all GET, under /v1.

Base URL: https://api.kcalbase.com. Keys are issued by hand during the preview; email support@kcalbase.com with your app name.

1. Search

curl -s "https://api.kcalbase.com/v1/foods/search?q=digestive&limit=3" \
  -H "Authorization: Bearer kb_live_YOUR_KEY"
const r = await fetch('https://api.kcalbase.com/v1/foods/search?q=digestive&limit=3', {
  headers: { Authorization: `Bearer ${process.env.KCALBASE_KEY}` },
});
const { results, matched, next_cursor } = await r.json();
import os, requests
r = requests.get("https://api.kcalbase.com/v1/foods/search",
                 params={"q": "digestive", "limit": 3},
                 headers={"Authorization": f"Bearer {os.environ['KCALBASE_KEY']}"})
for food in r.json()["results"]:
    print(food["name"], food["brand"], food["per_100"]["energy_kcal"])

matched is exact, fuzzy (we corrected a likely typo; say "showing results for") or none.

2. Barcode

curl -s https://api.kcalbase.com/v1/foods/barcode/5000159407236 -H "Authorization: Bearer kb_live_YOUR_KEY"

8, 12, 13 or 14 digits all work. 404 means we do not have it yet.

3. One food, and many at once

GET /v1/foods/{id} returns the same object search does. GET /v1/foods/lookup?barcodes=...&ids=... takes up to 50 items and returns found in your order plus missing as you sent them; it costs one request per 10 items. Send If-None-Match with the ETag you last saw and unchanged rows come back as 304.

The food object

Every route returns the same shape. per_100 is per 100 g or 100 ml (basis). Every serving carries grams and its own nutrients block scaled from per_100. null means the source did not say, never zero. attribution.required tells you whether you must show attribution.text (you must, for open-layer rows). quality and provenance tell you how much to trust a row and where it came from. Full field list in the API reference.

Headers you will see

Header Meaning
X-Request-Id Quote it when you report a problem.
X-Kcalbase-Data-Version, X-Kcalbase-Data-Updated Which data snapshot answered, and when it was ingested.
X-Kcalbase-Quota-Limit, -Used, -Remaining, -Reset Your monthly quota, on every metered response.
ETag Send it back as If-None-Match and an unchanged row answers 304: free of bandwidth, because there is no body, but it still counts one request against your monthly quota.
Cache-Control private, must-revalidate on every metered response: the answer carries your quota headers, so no shared cache may replay it and clients should revalidate with the ETag rather than serve a stale copy.
X-Kcalbase-Cache hit or miss. Hits still count as requests.