cook.md

Nutrition APICook Basic & Pro

The Nutrition API is the lookup service behind Cook's nutrition reports and the Nutrition MCP server. It resolves ingredient names the way they appear in a .cook file, scales them to an amount and unit, and returns calories, macros, micronutrients, vitamins and allergens, backed by USDA FoodData Central.

It lives at https://nutrition.cook.md. Use it from scripts, your own tools, or a report template; if you'd rather talk to it through an AI agent, the MCP server wraps the same endpoints as tools.

Endpoints

EndpointWhat it does
GET /nutritionNutrition for one ingredient at an amount, unit, preparation and region.
POST /aggregateSum nutrition across a list of ingredients (a recipe or a meal), up to 200 items, with per-item failures, exclusions and an allergen summary.
GET /ingredients/lookupResolve a name, alias or translation to a canonical ingredient, and see which preparations have data.
GET /categoriesList every category slug (dairy, tree nuts, and so on).
GET /categories/{slug}/checkIs an ingredient in a category? Walks the category tree.
GET /convertConvert an amount between mass, volume and count units for an ingredient.
GET /branded/lookupLook up a packaged product by UPC or by brand and description text.
GET /reference-intakesDaily reference-intake tables (FDA, EU, UK).
GET /attributionsData-source licences and citations. Public, no token needed.

The full request and response shapes are in the interactive reference and the OpenAPI 3.1 spec.

Who can use it

The API is included with Cook Basic and Cook Pro. It is not part of the free plan, and legacy free-sync accounts don't include it either. Report templates themselves are free and open source; the maintained nutrition data behind them is the part that costs money to run, which is why it sits with a subscription.

One honest limit: ingredient matching currently works for names written in English. Recipes in other languages sync and plan fine, but lookups for their ingredients come back as ingredient_not_found until more languages are added.

Authentication

Every endpoint except /attributions and /health needs a credential. There are two kinds.

Your Cook account (bearer token)

Personal use goes through a cook.md device login, the same flow the MCP server's login tool runs for you. From a terminal:

# 1. Ask cook.md for a device code
curl -X POST https://cook.md/oauth/device/code -d client_name="my nutrition script"
# returns user_code, device_code and a verification_uri_complete link

# 2. Open the verification_uri_complete link in your browser, sign in, and approve

# 3. Exchange the device code for a token
curl -X POST https://cook.md/oauth/device/token \
  -d grant_type=urn:ietf:params:oauth:grant-type:device_code \
  -d device_code=DEVICE_CODE
# returns {"access_token": "...", "token_type": "Bearer", "expires_in": ...}

Send the token as Authorization: Bearer <access_token>. Tokens expire; when a call starts returning 401, run the login again.

Organization API key

Teams and products that call the API on behalf of many users get an organization key, sent as the X-API-Key header. Keys are issued by hand for now: get in touch with what you're building and the volume you expect.

Quick start

Nutrition for 100 g of butter:

curl -H "Authorization: Bearer $COOKMD_TOKEN" \
  'https://nutrition.cook.md/nutrition?ingredient=butter&amount=100&unit=g'

A whole dish in one call:

curl -H "Authorization: Bearer $COOKMD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {"ingredient": "salmon", "amount": 150, "unit": "g", "prep": "cooked"},
      {"ingredient": "rice", "amount": 1, "unit": "cup", "prep": "cooked", "region": "us"},
      {"ingredient": "broccoli", "amount": 200, "unit": "g"}
    ],
    "reference": "eu"
  }' \
  https://nutrition.cook.md/aggregate

The response carries per-item results, totals (mass, macros, micros, vitamins and a confidence rating), any items that failed to resolve in failures[], and an allergen_summary. Every response also includes the daily reference-intake table for the standard you asked for (fda, eu or uk), so percent-of-daily-value is a division away.

Not sure how an ingredient is named? Resolve it first:

curl -H "Authorization: Bearer $COOKMD_TOKEN" \
  'https://nutrition.cook.md/ingredients/lookup?q=spring%20onion'

Tips

  • Prefer POST /aggregate for a recipe or meal instead of many /nutrition calls.
  • Volume units need a density. ml, l, tsp, tbsp and cup only work when a density is recorded for the ingredient and preparation. On density_unavailable, retry with a mass unit (g, kg, oz, lb).
  • region changes cup and spoon sizes. Valid values are us (default), uk and metric.
  • Preparation matters. prep defaults to raw; pass cooked, dried and so on to match how the ingredient is used. Lookup tells you which preparations have data.
  • Allergens are a floor, not a ceiling. allergen_summary.contains is the union over verified items. When unverified_ingredients is non-empty, never treat absence as allergen-free.
  • Errors help you self-correct. They follow RFC 9457 (application/problem+json) with a stable code plus field, received and suggestions. On ingredient_not_found, check suggestions or call lookup first.

Libraries & tools

  • Report templates. The nutrition functions available in Cook report templates (nutrition_for(), aggregate_nutrition(), the check macros) are this API behind a jinja surface, rendered in Cook Editor.
  • Rust. cookmd-nutrition-client is a small blocking HTTP client; cooklang-reports-nutrition plugs it into cooklang-reports. Both are open source (MIT).
  • AI agents. The Nutrition MCP server exposes every endpoint above as a tool for MCP-capable clients, plus a report-rendering loop.
  • For agents reading docs. llms.txt is a compact, agent-oriented summary of the API.

Where the data comes from

Nutrition values are measured laboratory data from USDA FoodData Central and other reference sources, not numbers guessed by an AI. Each response reports how confident the resolution is and which source it came from, so a report can say when an estimate is shaky. GET /attributions lists every source with its licence and citation.

Reference