Foodashi API

The complete recipe API for modern food applications. Search by flavor, nutrient, or ingredient with vector-powered semantic search.

Open Test Kitchen
Base URL api.foodashi.com
Format JSON
cURL JavaScript Python
# Get your first recipes
curl -X GET "https://api.foodashi.com/api/recipes?cuisine=italian&limit=5" \
  -H "X-Api-Key: YOUR_API_KEY"

Authentication

All API requests require authentication via the X-Api-Key header. You can register a new API key at our developer portal.

Security Best Practices

Your API keys carry many privileges, so be sure to keep them secure! Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, or blog posts.

Authentication Header
X-Api-Key: rcpt_indie_xK9d8sL2mN...

Authorization: Bearer <your API key> is accepted as an alternative to X-Api-Key, for clients and agent frameworks that can only send a Bearer token. Both headers pass the API's CORS preflight from an allowed origin.

Tier Access

Endpoints are gated by your subscription tier. If you call an endpoint above your plan, you'll receive a 403 response with upgrade details.

Hobby
Indie
Pro
View pricing
403 Upgrade Required Response
{
  "error": "Upgrade required",
  "code": "tier_required",
  "message": "This endpoint requires the pro plan or higher. Your current plan: hobby.",
  "current_tier": "hobby",
  "required_tier": "pro",
  "upgrade_url": "https://foodashi.com/pricing"
}

Plans & Rate Limits

Rate limits and endpoint access are tiered by subscription plan. Monthly quotas reset on your billing anchor date.

Plan Price Monthly Requests RPM API Keys
Hobby Free 10,000 30 1
Indie $25/mo · $250/yr 150,000 600 3
Pro $90/mo · $900/yr 1,000,000 3,000 10
Enterprise Custom 10,000,000+ 10,000+ Unlimited

Yearly billing = 10× monthly (two months free). Overage: $0.50 per 1,000 credits on Indie and $0.30 on Pro.

Key lookups. Apart from your plan’s RPM, one client address can make 120 API key lookups per minute. A key used in the last few seconds is not looked up again, so a working integration rarely meets this limit; unknown or invalid keys do count. Over it the answer is 429 rate_limited with "limit": 120, retry_after and a Retry-After header in seconds, and without the X-RateLimit-* headers.

What each tier unlocks

Hobby

25 endpoints: core browsing & reference.

  • • Recipe browse (by cuisine, diet, meal-type, time, difficulty)
  • • Ingredient search & food groups
  • • Nutrient & daily-value reference
  • • Utilities (convert, allergens, diets, cuisines)
  • • Requires a visible Powered by Foodashi credit

Indie

+ all Hobby

54 endpoints: search & matching.

  • • Full-text search & autocomplete
  • • Bulk lookup & similar recipes
  • • Browse by cooking method / equipment / occasion / season
  • • Recipes by ingredients (what's in my fridge)
  • • Recipe nutrition / allergens / beverages / scale
  • • NutriMetric scoring + FDA/EU nutrition labels
  • • Ingredient details, substitutes, portions, conversions
  • • Meal plan templates & basic shopping lists

Pro

+ AI

All 74 endpoints: everything + AI.

  • • AI meal plan generation + customization
  • • Food photo recognition (Vision): dish + ingredient detection
  • • Recipe analysis from text or URL
  • • Semantic vector search (ingredients)
  • • AI beverage pairing (sommelier)
  • • Recipe compare + taste / sustainability / medical profiles
  • • AI-optimized shopping lists
Calling an endpoint above your tier returns 403 with required_tier and upgrade_url fields so your app can handle upgrades gracefully.

Attribution

On the Hobby plan, wherever your app or site shows Foodashi data, it must show a visible “Powered by Foodashi” credit that links to https://foodashi.com. Indie, Pro and Enterprise plans need no Foodashi credit: you can present the data entirely under your own brand.

Visible means a reader can see and follow it without opening a menu: next to the data, or in the footer of the same page or screen. In a native app, a text button that opens https://foodashi.com in the browser does the same job. Copy this snippet:

HTML
<p class="foodashi-credit"><a href="https://foodashi.com">Powered by Foodashi</a></p>

Style it to fit your design, as long as the text stays readable and the link works. This credit is separate from the open-database credits that apply on every plan: if you show nutrition, ingredient or barcode data, also link to foodashi.com/data-sources somewhere your users can find it. The full terms are in the API License Agreement, Section 6.

Error Handling

Status Meaning
200 Success
400 Bad Request - Invalid parameters
401 Unauthorized - Missing or invalid API key
403 Forbidden: plan does not include this endpoint (code tier_required), account suspended (account_suspended) or key over the plan key count (key_limit_exceeded)
404 Not Found - Endpoint doesn't exist
429 Too Many Requests: code rate_limited (per-minute; Retry-After in seconds), quota_exceeded or overage_depleted (monthly allowance; Retry-After = seconds to the reset on the 1st, 00:00 UTC), trial_exhausted. rate_limited is your plan’s per-minute limit, or too many API key lookups from one client address (120 per minute, see rate limits). overage_depleted means your prepaid extra usage cannot pay for the call; a balance check that did not answer is a 503, never this.
413 Payload Too Large: code payload_too_large. A body over 1 MB is refused (6 MB for image recognition and beverage pairing); some endpoints set a smaller limit and name it in limit_bytes, beside received_bytes.
500 Server Error - Something went wrong on our end
503 Service Unavailable: code service_unavailable with "retryable": true. Your account’s quota or extra-usage check, or a read of the data behind the answer, did not answer: nothing partial was served, so send the same request again after a short wait. It is never a quota verdict (that is a 429). On the AI endpoints a 503 can also mean the AI step or the AI usage check was unavailable; retry in a minute. A barcode lookup can also answer upstream_rate_limited (with Retry-After) or upstream_unavailable.
Error Response
{
  "error": "Rate Limit Exceeded",
  "code": "quota_exceeded",
  "message": "Monthly Quota Exceeded",
  "retry_after": 561600,
  "upgrade_url": "https://foodashi.com/pricing"
}

Every error body carries a stable machine-readable code (for example invalid_parameter, unknown_parameter, invalid_allergen, invalid_id, offset_too_deep, not_found, unauthorized, missing_api_key, invalid_api_key, service_unavailable). Branch on code; the error and message text may change. Report a Recipe has its own codes: invalid_report, customer_key_required, recipe_not_found and report_limit_exceeded.

Authorization: Bearer <your API key> is accepted as an alternative to X-Api-Key; both pass the CORS preflight from an allowed origin.

GET /api/recipes Hobby+ 1 credit

Get Recipes

Retrieve a list of recipes with powerful filtering options. Supports pagination, dietary filters, cuisine selection, and detailed metadata filtering.

Query Parameters

Parameter Type Description
page integer Page number for pagination, 1-based (default: 1). Ignored when random=true.
limit integer Results per page (default: 20, max: 100).
offset integer Row offset (alternative to page).
random boolean Return a shuffled sample instead of stable pagination. Aliases: sort=random, shuffle=true. See browse conventions.
cuisine string
Filter by cuisine. Title-case match (case-insensitive accepted).
🌍 Browse all 80 supported cuisines ▾
🥡 East / Southeast Asia
JapaneseChineseKoreanThaiVietnameseIndonesianMalaysianFilipinoSingaporeanBurmeseCambodianLaotian
🍛 South / Central Asia
IndianPakistaniSri LankanBangladeshiNepaleseTibetanAfghan
🥙 Middle East
TurkishLebanesePersianSyrianIraqiIsraeliSaudi ArabianYemeni
🌶️ North Africa
MoroccanTunisianEgyptian
🥖 Europe
ItalianFrenchSpanishGreekPortugueseGermanBritishIrishPolishRussianUkrainianHungarianGeorgianAustrianBelgianCzech
❄️ Nordic
DanishSwedishNorwegianFinnishIcelandic
🌎 Americas
AmericanMexicanBrazilianPeruvianArgentineColombianVenezuelanChileanBolivianEcuadorian
🏝️ Caribbean
CubanJamaicanHaitianDominicanPuerto RicanTrinidadianBarbadian
🌺 Pacific
HawaiianAustralian
🥘 Sub-Saharan Africa
EthiopianNigerianSouth AfricanGhanaianSenegaleseTanzanianKenyan
🌐 Catch-all
Global
diet string Dietary tag, case-insensitive; CSV means all listed; unknown value returns 400 with valid_diets.
exclude_alg string Comma-separated allergens to exclude. Case-insensitive EU-14 names: Gluten, Crustaceans, Eggs, Fish, Peanuts, Soy, Dairy, Tree Nuts, Celery, Mustard, Sesame, Sulfites, Lupin, Molluscs (synonyms Soybeans, Milk, Wheat, Nuts, Sulphites accepted). Aliases: allergen, exclude_allergens. "Shellfish" is ambiguous: use Crustaceans and/or Molluscs. Any unknown name returns 400 invalid_allergen.
meal_type string
Filter by when/how it's eaten. Recipes carry 1-5 values (multi-value array); matches if any value matches.
⏰ Browse all 16 meal_type values ▾
🕐 Time of day
BreakfastBrunchLunchDinnerLate Night
🍽️ Course position
AppetizerSideMain CourseDessert
☕ Between-meal & context
SnackTea TimeAperitifDrinkStreet Food
🧂 Non-meal accessory
CondimentComponent
dish_type string
Filter by structural identity — what the dish IS in form. Recipes carry 1-3 values (multi-value array); matches if any value matches.
🍽️ Browse all 107 dish_type values ▾
💧 Liquid
SoupStewCurryPorridge
🌯 Hand-held
SandwichWrapBurgerHot DogSpring Roll
🍝 Pasta & Noodle
PastaNoodle DishStuffed Pasta
🍚 Rice
Rice DishFried RiceSushi
🌾 Grain
Grain Dish
🥗 Salad & Raw
SaladSlawCevicheTartare
🔥 Cooking method
Stir-FryGrilled DishRoastBraised DishSteamed DishBarbecueSkewerFried Dish
🍳 Fritter family
FritterCutletCroquette
🥘 Baked savory
CasseroleGratinQuicheSavory PieSoufflé
🥟 Filled dough
DumplingEmpanadaHand Pie
🍕 Pizza & Flatbread
PizzaCalzoneStuffed Flatbread
🍞 Bread
BreadFlatbreadCornbread
🥞 Pancake
PancakeCrepeWaffle
🥚 Egg
OmeletScrambled EggsEgg Dish
🫘 Legume
Bean DishLentil DishTofu Dish
🥕 Vegetable
Vegetable DishStuffed Vegetable
🧀 Cheese
FondueCheese Plate
🧂 Cured & Sausage
SausageCharcuterieCured FishJerky
🥩 Meat
SteakRoast MeatRibsMeatballGround Meat Dish
🐠 Seafood
Fish FilletWhole FishShellfish
🍰 Sweet families
CakeCheesecakeCookieSweet PiePastryPuddingCustardFrozenConfectionJellyAssembledCrumble
🥛 Yogurt
Yogurt Dish
🥄 Sauce & Condiment
SauceDressingMarinadeDipSpreadSpice Paste
🥒 Pickle & Preserve
PickleJamCompote
🥤 Beverage (use with meal_type=Drink)
SmoothieMilkshakeJuiceCocktailMocktailTeaCoffeeHot ChocolateFermented Beverage
🥨 Pantry & Snack
CrackerGranolaEnergy BarPopcorn
🍱 Plate format
Mixed PlateBowl
difficulty string Filter by difficulty ("Easy", "Medium", "Hard", "Expert"), case-insensitive
equipment string Filter by required equipment (e.g., "Blender", "Air Fryer")
tag string Filter by specific custom tags (e.g., "Authentic", "Spicy")
time integer Maximum cook time in minutes (cook_time_minutes)
total_time integer Maximum total time (prep + cook) in minutes
min_nutrimetric integer Minimum NutriMetric score (0-100)
cost_tier string Filter by estimated cost ("cheap", "moderate", "expensive")
search string Text search in recipe titles (alias: q)

Unknown query parameters return 400 with code unknown_parameter and the list of accepted_parameters. Pages past offset 1000 return 400 with code offset_too_deep; pagination.total_pages counts only servable pages (pages_truncated tells you when more match).

cURL JavaScript Python
curl -X GET "https://api.foodashi.com/api/recipes?cuisine=Mexican&exclude_alg=Peanuts&limit=2" \
  -H "X-Api-Key: YOUR_API_KEY"

Example Response

200 OK
{
  "data": [
    {
      "id": "a1b2c3d4-...",
      "title": "Spaghetti Carbonara",
      "cuisine": "Italian",
      "meal_types": ["Dinner", "Main Course"],
      "dish_types": ["Pasta"],
      "difficulty": "Medium",
      "total_time_minutes": 30,
      "servings": 4,
      "image_url": "https://...",
      "dietary_tags": ["Nut-Free"],
      "tags": ["pasta", "comfort-food"]
    }
  ],
  "pagination": { "page": 0, "limit": 10, "total": 86 }
}
GET /api/recipes/details Hobby+ 1 credit

Recipe Details

Get complete details for a single recipe including full ingredients, step-by-step instructions, nutrition info, taste profile, and storage metadata.

Query Parameters

Parameter Type Description
id Required string (UUID)Required The recipe ID, a UUID (e.g. b1a2c3d4-e5f6-7890-abcd-ef1234567890)
cURL JavaScript Python
curl -X GET "https://api.foodashi.com/api/recipes/details?id=b1a2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "X-Api-Key: YOUR_API_KEY"

Example Response

200 OK
{
  "id": "a1b2c3d4-...",
  "title": "Truffle Risotto",
  "description": "Creamy arborio rice with...",
  "cuisine": "Italian",
  "ingredients": [
    { "name": "Arborio Rice", "amount": "300g" },
    { "name": "Truffle Oil", "amount": "2 tbsp" }
  ],
  "instructions": ["Toast rice in butter...", "Add broth gradually..."],
  "nutrition": {
    "calories": 420,
    "protein_g": 12,
    "fat_g": 18,
    "carbs_g": 52
  },
  "nutrimetric": {
    "grade": "B",
    "score": 72,
    "label": "Good",
    "version": "nutrimetric-1.0"
  }
}

nutrimetric and beverage_pairing are paid fields (Indie plan and above). A Hobby key receives a {"locked": true, ...} marker in their place; see Paid Fields.

GET /api/random Hobby+ 1 credit

Random Recipe

Returns a random recipe, great for "Surprise Me" features. Every filter is optional and they combine.

ParameterTypeDescription
tagsstringCSV; each token must match a meal type (dinner), dish type (soup) or recipe tag
cuisinestringCuisine name, case-insensitive (e.g. Italian)
dietstringDietary tag, case-insensitive; CSV means all listed; unknown value returns 400 with valid_diets
meal_typestringMeal type (e.g. Dinner)
dish_typestringDish type (e.g. Soup)
exclude_allergensstringCSV of EU-14 allergens to exclude, case-insensitive (aliases allergen, exclude_alg); an unknown name returns 400 invalid_allergen
countinteger1-10, default 1
Example
curl -X GET "https://api.foodashi.com/api/random?tags=dinner" \
  -H "X-Api-Key: YOUR_API_KEY"

count=1 returns one recipe object; count>1 returns {recipes, count} (plus partial and failed_ids if a recipe could not be formatted).

Browse conventions (read once, applies everywhere)

Every /api/recipes/by-* endpoint — plus /api/recipes, /api/recipes/filter, /api/ingredients/by-food-group, and /api/ingredients/:id/recipes — supports the same set of query conventions. Learn these once, use them everywhere.

Pagination (default behaviour)

ParameterTypeDescription
pageintegerPage number, 1-based (default: 1).
limitintegerResults per page (default: 20, max: 100). For ingredient endpoints max is 50.
offsetintegerRow offset; wins over page.
Past offset 1000: 400 with code offset_too_deep.

Default ordering: newest-published first. Every response includes a pagination object with page, limit, total, and total_pages. total_pages counts only the pages that can be served; when more recipes match, pages_truncated is true.

Random mode — new 2026-05-10

When you want a fresh sample on every request (e.g. "surprise me" / "explore" UI), pass any of:

ParameterValueNotes
randomtrueMost common form.
sortrandomAlternative spelling (consistent with the sort param on /api/recipes/filter).
shuffletrueAlternative spelling.

All three forms are accepted; pick whichever fits your code style. Each call reads a window of matching recipes at a random position in the whole matching set and shuffles it, so every matching recipe can appear. Pagination is meaningless in random mode: each request is its own independent sample.

Example
curl -X GET "https://api.foodashi.com/api/recipes/by-cuisine?cuisine=Italian&random=true&limit=5" \
  -H "X-Api-Key: YOUR_API_KEY"

# Same call again returns 5 DIFFERENT Italian recipes
curl -X GET "https://api.foodashi.com/api/recipes/by-cuisine?cuisine=Italian&random=true&limit=5" \
  -H "X-Api-Key: YOUR_API_KEY"

Year-Round is a wildcard for season queries

A recipe explicitly tagged Year-Round is good in every season — so it surfaces in any specific-season query (Spring/Summer/Fall/Winter). The recipe’s seasons array doesn’t need to contain "Spring" for it to appear when you query ?season=Spring; if it contains Year-Round, it qualifies.

  • • ?season=Spring → matches recipes whose seasons[] overlaps [Spring, Year-Round]
  • • ?season=Summer → matches [Summer, Year-Round]
  • • ?season=Fall → matches [Fall, Year-Round] — alias: ?season=Autumn
  • • ?season=Winter → matches [Winter, Year-Round]
  • • ?season=Year-Round → strict: only recipes explicitly tagged Year-Round

This semantic applies to both /api/recipes/by-season and /api/recipes/filter?season=….

String matching — case & plural tolerance

Ingredient-based endpoints (/api/recipes/by-ingredients, /api/ingredients/:id/recipes text fallback) normalise input before matching:

  • • Case-insensitive: red onion = Red Onion = RED ONION
  • • Whitespace collapsed: red  onion (double space) = red onion
  • • Plural-tolerant: onion = onions, tomato = tomatoes, cherry = cherries
  • • Substring match: chicken matches "chicken breast", "ground chicken", etc. Use longer phrases for specificity.
  • • Typo-intolerant: red onon returns 0 — call /api/ingredients/autocomplete first if you need fuzzy/typo handling.

Taxonomy filters — include & exclude (works on every browse endpoint)

Every /api/recipes/by-* browse endpoint and /api/recipes/filter accept these optional taxonomy filters. They combine with the endpoint’s own filters (diet, exclude_allergens, max_time_minutes, difficulty, has_image, …). All values are case-insensitive, resolved against the two-axis taxonomy, and unknown values are silently ignored (never an error).

ParameterTypeDescription
meal_type / meal_typesCSVInclude recipes whose meal_types[] match any listed value. Example: meal_types=Dinner,Lunch.
dish_type / dish_typesCSVInclude recipes whose dish_types[] match any listed value. Example: dish_types=Pasta,Pizza.
exclude_meal_typesCSVDrop recipes whose meal_types[] match any listed value. Example: exclude_meal_types=Dessert,Appetizer,Side.
exclude_dish_typesCSVDrop recipes whose dish_types[] match any listed value. Example: exclude_dish_types=Salad,Cake.
exclude_dietsCSVDrop recipes tagged with any listed diet. Example: exclude_diets=Vegan.
min_time_minutes / max_time_minutesintegerTotal-time bounds (prep + cook + rest), in minutes. Combine the two for a range. See the time fields for how total, active and rest relate.
Example — Italian main dishes, no desserts / starters / salads
curl -X GET "https://api.foodashi.com/api/recipes/by-cuisine?cuisine=Italian&exclude_meal_types=Dessert,Appetizer,Side&exclude_dish_types=Salad&limit=100" \
  -H "X-Api-Key: YOUR_API_KEY"

Unknown parameters are refused

Every /api/recipes/by-* endpoint answers a parameter name it does not read with 400 and code unknown_parameter: unknown_parameters names it and accepted_parameters lists every name that endpoint reads, so a misspelt filter never returns an unfiltered page that looks filtered. The cache buster _ is accepted.

To exclude allergens on any /api/recipes/by-* endpoint, send exclude_allergens (aliases exclude_alg and allergen) with case-insensitive EU-14 names, as on /api/recipes; an unknown name is a 400 with code invalid_allergen. /api/recipes/filter takes exclude_allergens only: the two aliases are refused there with 400 unknown_parameter. /api/recipes/by-ingredients applies the allergen exclusion and the taxonomy filters above before it counts its total and cuts its page.

GET /api/recipes/by-cuisine Hobby+ 1 credit

Browse by Cuisine

Browse recipes filtered by cuisine type. Returns lightweight recipe cards with pagination.

ParameterTypeDescription
cuisine RequiredstringRequiredCuisine name (e.g., "Italian", "Mexican", "Japanese")
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
cURL JavaScript Python
curl -X GET "https://api.foodashi.com/api/recipes/by-cuisine?cuisine=Italian&limit=10" \
  -H "X-Api-Key: YOUR_API_KEY"
Narrow it down: this endpoint (and every /api/recipes/by-* browse endpoint) also accepts the optional taxonomy filters — meal_type/meal_types and dish_type/dish_types (CSV, match any), the exclude_meal_types/exclude_dish_types/exclude_diets drop-lists, and min_time_minutes/max_time_minutes. All case-insensitive and optional. See browse conventions.
GET /api/recipes/by-cuisine?cuisine=Italian&exclude_meal_types=Dessert,Appetizer,Side&exclude_dish_types=Salad&limit=100
→ Italian main dishes, no desserts / starters / salads.
GET /api/recipes/by-region Hobby+ 1 credit

Browse by Region

Group recipes by sub-continental region (e.g. Southeast Asia covers Thai + Vietnamese + Malaysian + Indonesian + Filipino in one call). Perfect for regional food landing pages.

ParameterTypeDescription
regionRequiredstringOne of: East Asia, Southeast Asia, South Asia, Central Asia, Middle East, North Africa, Sub-Saharan Africa, Southern Europe, Western Europe, Northern Europe, Eastern Europe, North America, Latin America, Caribbean, Oceania, Global
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
cURL JavaScript Python
curl -X GET "https://api.foodashi.com/api/recipes/by-region?region=Southeast%20Asia&limit=20" \
  -H "X-Api-Key: YOUR_API_KEY"

Response shape: { recipes: [...], filter: { region }, pagination: { page, limit, total } }

GET /api/recipes/by-continent Hobby+ 1 credit

Browse by Continent

Broadest geographic filter. Useful for top-level navigation like “Asian cuisine” or “European cuisine”.

ParameterTypeDescription
continentRequiredstringOne of: Asia, Europe, Africa, Americas, Oceania, Global
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
cURL JavaScript Python
curl -X GET "https://api.foodashi.com/api/recipes/by-continent?continent=Asia&limit=30" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-country Hobby+ 1 credit

Browse by Country

Filter recipes by a specific country using its ISO-3166-1 alpha-2 code (e.g. JP for Japan, IT for Italy, MX for Mexico). Perfect for country-flag navigation UIs.

ParameterTypeDescription
countryRequiredstringISO-3166-1 alpha-2 country code (case-insensitive). Example: JP, IT, BR, MX, IN, MY.
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
cURL JavaScript Python
curl -X GET "https://api.foodashi.com/api/recipes/by-country?country=JP&limit=25" \
  -H "X-Api-Key: YOUR_API_KEY"

Response includes filter.cuisines_in_country — the list of cuisines mapped to that country, so you can display them as sub-filters in your UI.

GET /api/recipes/filter Indie+ 1 credit

Multi-Filter Search

The power user’s endpoint. Combine any subset of the filters below in a single call — location, diet, time, cost, equipment, tags, nutrition, sort. All filters are optional and AND-combined. Empty filter values are ignored.

Power example: "Spring salads under 30 min that are vegan and serve 4+" →
?season=Spring&dish_type=Salad&max_time_minutes=30&diet=Vegan&min_servings=4

For valid values of each param, jump to the Reference: Valid values section.

Filters — Location

ParameterTypeDescription
cuisinestringExact cuisine name. See 80 valid cuisines. Example: Italian, Thai, Sri Lankan.
regionstringSub-continental region. See 14 valid regions. Example: Southeast Asia, Southern Europe.
continentstringAfrica, Americas, Asia, Europe, or Oceania.
countrystringISO-3166-1 alpha-2 code (alias country_code). Maps to all cuisines for that country. Example: JP, IT, MX. A code with no cuisine returns 400.

Filters — Type, Style & Difficulty

ParameterTypeDescription
meal_type / meal_typesstring / CSVWHEN it’s eaten. See 16 valid meal types. Example: Breakfast, Dinner, Snack. Accepts a comma-separated list (alias meal_types) — matches recipes whose meal_types[] include any listed value. Case-insensitive; unknown values are ignored. Example: meal_types=Dinner,Lunch.
dish_type / dish_typesstring / CSVWHAT it structurally is. See 107 valid dish types. Example: Salad, Soup, Curry, Pasta, Cake. Different from meal_type — a Salad can be a Lunch, a Side, or a Main. Accepts a comma-separated list (alias dish_types) — matches recipes whose dish_types[] include any listed value. Case-insensitive; unknown values are ignored. Example: dish_types=Pasta,Pizza.
exclude_meal_typesCSVComma-separated meal types — drop recipes whose meal_types[] include any listed value. Case-insensitive; unknown values ignored. Example: exclude_meal_types=Dessert,Appetizer,Side.
exclude_dish_typesCSVComma-separated dish types — drop recipes whose dish_types[] include any listed value. Case-insensitive; unknown values ignored. Example: exclude_dish_types=Salad,Cake.
difficultystringEasy, Medium, or Hard.

Filters — Diet, Tags & Allergens

ParameterTypeDescription
dietstringOne dietary tag the recipe must satisfy. See 11 dietary tags. Example: Vegan, Gluten-Free.
exclude_dietsCSVComma-separated dietary tags — drop recipes tagged with any listed diet. Case-insensitive; unknown values ignored. Example: exclude_diets=Vegan.
tagstringSingle free-form tag the recipe must have. Example: weeknight-dinner, comfort-food.
include_tagsCSVComma-separated tags — recipe must contain all of them. Example: comfort-food,weeknight-dinner.
exclude_tagsCSVComma-separated tags — recipe must contain none of them.
exclude_allergensCSVEU-14 allergens to filter out. See 14 valid allergens. Example: Eggs,Dairy,Nuts.

Filters — Time, Servings & Cost

ParameterTypeDescription
max_time_minutesintegerMax total time (prep + cook + rest), in minutes. Because rest is included, a low value correctly excludes dishes needing an overnight marinade. List responses carry the total only; the hands-on figure, active_time_minutes, is on the full recipe from /api/recipes/details.
min_time_minutesintegerMin total time. Combine with max_time_minutes for a range.
min_servingsintegerMinimum servings (useful for batch cooking).
max_servingsintegerMaximum servings.
servingsintegerExact servings.
max_prep_minutesintegerMax prep time, in minutes.
cost_level_maxinteger1 (budget) to 4 (luxury).

Filters — Technique & Context

ParameterTypeDescription
cooking_methodstringSingle technique. See 59 valid methods. Example: baked, grilled, steamed, stir-fried.
equipmentstringSingle piece of equipment the recipe uses. Example: wok, cast iron skillet, oven, slow cooker.
occasionstringSee 7 valid occasions. Example: Weeknight, Holiday, Barbecue.
seasonstringSpring, Summer, Fall (or alias Autumn), Winter, or Year-Round. Year-Round acts as a wildcard — year-round recipes appear in every specific-season query. See browse conventions.

Filters — Nutrition & Quality

ParameterTypeDescription
min_caloriesnumberMin kcal per serving.
max_caloriesnumberMax kcal per serving.
min_protein_gnumberMin grams of protein per serving.
max_protein_gnumberMax grams of protein per serving.
min_fat_gnumberMin grams of fat per serving.
max_fat_gnumberMax grams of fat per serving.
min_carbs_gnumberMin grams of carbohydrate per serving.
max_carbs_gnumberMax grams of carbohydrate per serving.
min_fiber_gnumberMin grams of fiber per serving.
max_sugar_gnumberMax grams of sugars per serving.
max_sodium_mgnumberMax milligrams of sodium per serving.
nutrimetric_min_gradestringFoodashi NutriMetric grade gate. A, B, C, D, E or F. Value passes if recipe’s grade is ≥ requested grade (A is best).
has_imagebooleantrue = only recipes with images; false = only without.

Sort & Pagination

ParameterTypeDescription
sortstringrecent (default, newest first; alias newest), time_asc (fastest first), time_desc, nutrimetric (best score first), or random.
randombooleanShuffle results — see browse conventions.
limitintegerResults per page (default: 20, max: 100).
pageintegerPage number (default: 1).
offsetintegerRow offset; wins over page. Past 1000 returns 400 offset_too_deep.

Nutrient bounds are per serving and compared as numbers. Malformed numbers, an unknown sort, grade or country code and unknown parameters return 400 (code invalid_parameter or unknown_parameter).

Examples

Quick weeknight dinners (under 30 min, max difficulty medium)

cURL JavaScript Python
curl -X GET "https://api.foodashi.com/api/recipes/filter?meal_type=Dinner&max_time_minutes=30&difficulty=Easy&sort=time_asc&limit=50" \
  -H "X-Api-Key: YOUR_API_KEY"

Healthy high-protein vegan meals (Grade B+, min 25g protein)

cURL JavaScript
curl -X GET "https://api.foodashi.com/api/recipes/filter?diet=Vegan&min_protein_g=25&nutrimetric_min_grade=B&sort=nutrimetric&limit=30" \
  -H "X-Api-Key: YOUR_API_KEY"

Mediterranean cuisine, no eggs or nuts, with image, Grade A nutrition

cURL
curl -X GET "https://api.foodashi.com/api/recipes/filter?region=Southern%20Europe&exclude_allergens=Eggs,Nuts&has_image=true&nutrimetric_min_grade=A&limit=100" \
  -H "X-Api-Key: YOUR_API_KEY"

Response Shape

200 OK
{
  "recipes": [
    { "id", "title", "title_english", "cuisine", "cuisine_code",
      "image_url", "total_time_minutes", "difficulty", "meal_types",
      "dish_types", "dietary_tags", "servings", "tags", "published_at" }
  ],
  "filter": { // The parameters applied, echoed back so you can verify your query was parsed correctly
    "cuisine": "Italian",
    "max_time_minutes": 30,
    "sort": "time_asc"
  },
  "pagination": { "page": 1, "limit": 50, "total": 342, "total_pages": 7 }
}

Performance tips

  • • All filters resolve to indexed columns — even combining 10 filters returns in <200ms.
  • • Use include_tags sparingly; it performs a GIN array-contains scan. Max 10 tags.
  • • limit=100 is the ceiling. For >100 results, paginate with page=2, etc.
  • • filter in the response echoes the parameters the server applied; a misspelt parameter name returns 400 unknown_parameter instead of being ignored.

Reference: Valid values

Every filter param above expects an exact value from one of the catalogues below. Case-sensitive unless noted. Copy-paste straight into your query string.

dish_type — 107 valid values

Pass to dish_type=. Describes what the dish structurally is — different from meal_type (when it's eaten). A "Salad" can be a Lunch, a Side, or a Main.

Liquid & Stews
SoupStewCurryPorridge
Hand-held
SandwichWrapBurgerHot DogSpring Roll
Pasta & Noodles
PastaNoodle DishStuffed Pasta
Rice
Rice DishFried RiceSushiGrain Dish
Salad & Raw
SaladSlawCevicheTartare
Cooking-method dishes
Stir-FryGrilled DishRoastBraised DishSteamed DishBarbecueSkewerFried Dish
Fritter family
FritterCutletCroquette
Baked savory
CasseroleGratinQuicheSavory PieSoufflé
Filled dough
DumplingEmpanadaHand Pie
Pizza, Flatbread & Bread
PizzaCalzoneStuffed FlatbreadBreadFlatbreadCornbread
Pancake
PancakeCrepeWaffle
Egg dishes
OmeletScrambled EggsEgg Dish
Legume & Vegetable
Bean DishLentil DishTofu DishVegetable DishStuffed Vegetable
Cheese & Cured
FondueCheese PlateSausageCharcuterieCured FishJerky
Meat & Seafood
SteakRoast MeatRibsMeatballGround Meat DishFish FilletWhole FishShellfish
Sweets
CakeCheesecakeCookieSweet PiePastryPuddingCustardFrozenConfectionJellyAssembledCrumble
Sauces & Condiments
SauceDressingMarinadeDipSpreadSpice PasteYogurt Dish
Pickle & Preserve
PickleJamCompote
Beverages
SmoothieMilkshakeJuiceCocktailMocktailTeaCoffeeHot ChocolateFermented Beverage
Snack format & Plate
CrackerGranolaEnergy BarPopcornMixed PlateBowl

meal_type — 16 valid values

Pass to meal_type=. Describes WHEN it's eaten or its role at the table. Different recipes can share a dish_type but have different meal_types (a Salad can be Lunch, Side, or Main).

Time-of-day
BreakfastBrunchLunchDinnerLate Night
Course within a meal
AppetizerSideMain CourseDessert
Between-meal & context
SnackTea TimeAperitifDrinkStreet Food
Accessory roles
CondimentComponent

cuisine — 80 valid values

Pass to cuisine=. Case-sensitive exact match.

Europe
AustrianBelgianBritishCzechDanishFinnishFrenchGeorgianGermanGreekHungarianIcelandicIrishItalianNorwegianPolishPortugueseRussianSpanishSwedishUkrainian
East Asia
ChineseJapaneseKoreanTibetan
Southeast Asia
BurmeseCambodianFilipinoIndonesianLaotianMalaysianSingaporeanThaiVietnamese
South Asia
AfghanBangladeshiIndianNepalesePakistaniSri Lankan
Middle East & North Africa
AlgerianArmenianEgyptianIraqiIsraeliLebaneseMoroccanPersianSaudi ArabianSyrianTunisianTurkishYemeni
Sub-Saharan Africa
BenineseEthiopianGhanaianKenyanNigerianSenegaleseSouth AfricanTanzanian
Americas (North)
AmericanHawaiianMexican
Americas (Latin & Caribbean)
ArgentineBarbadianBolivianBrazilianChileanColombianCubanDominicanEcuadorianHaitianJamaicanPeruvianPuerto RicanTrinidadianVenezuelan
Oceania
Australian

region — 14 valid values

Pass to region=. Sub-continental grouping.

CaribbeanEast AsiaEastern EuropeLatin AmericaMiddle EastNorth AfricaNorth AmericaNorthern EuropeOceaniaSouth AsiaSoutheast AsiaSouthern EuropeSub-Saharan AfricaWestern Europe

continent — 5 valid values

AfricaAmericasAsiaEuropeOceania

diet: 21 dietary tags

Pass to diet=. Recipe must satisfy this dietary constraint. Note: include_tags / exclude_tags use a different (free-form) tag namespace; this diet param is the curated dietary-restriction list.

VegetarianVeganPescatarianPaleoWhole30KetoLow-CarbHigh-ProteinLow-FatLow-SodiumLow-SugarGluten-FreeDairy-FreeEgg-FreeSoy-FreeNut-FreeShellfish-FreeLow-FODMAPDiabetic-FriendlyHeart-HealthyMediterranean

exclude_allergens — EU-14 list

Pass a CSV like exclude_allergens=Eggs,Dairy,Nuts. Mapped to EU Regulation 1169/2011 — recipes containing any listed allergen are filtered out.

GlutenCrustaceansEggsFishPeanutsSoybeansDairyTree NutsCeleryMustardSesameSulfitesLupinMolluscs

cooking_method — 59 valid values

Pass to cooking_method=. Lowercase. Single value (intersect with other filters for AND).

bakedblanchedblendedboiledbraisedbriningbrowningcaramelizingchillingcookedcoolingcrystallizingcuringdeep fryingdeep-frieddry-frieddum-cookingfermentedfermentingfriedgriddle-cookinggriddlinggrilledgrindingkneadingmarinatedmarinatingmashingmeltingmixingno-cookoven dryingpan-friedpar-fryingpickledpicklingpoachedproofingrawreducingrisingroastedsauteedscorchingsearedsettingsimmeredsmokedsoakingsteamedstir-friedtemperingtoastedtoastingtossingwater-bathwhippedwhisking

occasion — 7 valid values

Pass to occasion=. Title-case.

EverydayWeeknightFamily MealMeal PrepBarbecuePartyHoliday

season — 5 valid values

Pass to season=. Case-insensitive. Autumn is accepted as an alias for Fall. Year-Round acts as a wildcard — year-round recipes appear in every specific-season query.

SpringSummerFallWinterYear-Round

equipment — 300+ values (free-form)

Pass to equipment=. The catalog has 300+ distinct equipment names — pass any specific one for an exact match. Common values:

wokovenblenderfood processorgrillgrill pancast iron skilletdutch ovenslow cookerrice cookermortar and pestlestand mixerhand mixersteamertagineclaypotdeep fryermicrowavewaffle ironrolling pinmandoline

country — ISO 3166-1 alpha-2 codes

Pass an ISO country code to country=. Foodashi maps it to all cuisines with that flag (e.g. US covers American, Hawaiian, Cajun, Creole). Common examples:

JPITFRMXCNINTHVNGRESPTBRARUSGBDEKRTR
GET /api/recipes/by-diet Hobby+ 1 credit

Browse by Diet

Filter recipes by dietary tag. Searches within the recipe's dietary_tags array.

ParameterTypeDescription
diet RequiredstringRequiredDietary tag (e.g., "Vegan", "Keto", "Gluten-Free")
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/by-diet?diet=Vegan&limit=10" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-meal-type Hobby+ 1 credit

Browse by Meal Type

Filter recipes by meal type such as Breakfast, Lunch, Dinner, Snack, or Dessert.

ParameterTypeDescription
type RequiredstringRequiredMeal type (e.g., "Breakfast", "Dinner", "Dessert")
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/by-meal-type?type=Breakfast" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-time Hobby+ 1 credit

Browse by Time

Find quick recipes by specifying a maximum total cook time in minutes.

ParameterTypeDescription
maxMinutesintegerRequiredMaximum total time in minutes (e.g., 30)
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/by-time?maxMinutes=30" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-difficulty Hobby+ 1 credit

Browse by Difficulty

Filter recipes by difficulty level: Easy, Medium, or Hard.

ParameterTypeDescription
difficulty RequiredstringRequiredDifficulty level: "Easy", "Medium", or "Hard"
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/by-difficulty?difficulty=Easy" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/count Hobby+ 1 credit

Recipe Count

Get the total number of published recipes. Supports optional filters to count subsets.

ParameterTypeDescription
cuisinestringFilter by cuisine
dietstringFilter by dietary tag
difficultystringFilter by difficulty
Example
curl -X GET "https://api.foodashi.com/api/recipes/count?cuisine=Italian" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/cuisines Hobby+ 1 credit

List Cuisines

Get all cuisines that have published recipes, with recipe counts for each.

Example
curl -X GET "https://api.foodashi.com/api/recipes/cuisines" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/tags Hobby+ 1 credit

List Tags

Get all recipe tags with counts. Useful for building tag clouds or filter UIs.

Example
curl -X GET "https://api.foodashi.com/api/recipes/tags" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/diets Hobby+ 1 credit

List Dietary Tags

Get all dietary tags with recipe counts. Useful for dietary filter UIs.

Example
curl -X GET "https://api.foodashi.com/api/recipes/diets" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/autocomplete Indie+ 1 credit

Autocomplete

Extremely fast search for UI search bars. Returns lightweight titles matching the query.

ParameterTypeDescription
querystringRequiredSearch text (min 2 chars)
limitintegerMax results (default 5, max 10)
Example
curl -X GET "https://api.foodashi.com/api/autocomplete?query=chick" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/bulk-lookup Indie+ 2 credits

Bulk Lookup

Fetch details for multiple recipes in a single API call. Essential for "Favorites" lists.

ParameterTypeDescription
idsstringRequiredComma-separated recipe UUIDs (max 50). Ids that are not UUIDs come back in invalid_ids.
Example
curl -X GET "https://api.foodashi.com/api/bulk-lookup?ids=3f8a1c2e-9b4d-4e6f-8a2b-1c3d5e7f9a0b,9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/similar Indie+ 1 credit

Similar Recipes

Recipes from the same cuisine, those sharing a dish type with the source first, newest first. Perfect for "You might also like" features. Optional narrowing: diet, meal_type, dish_type and exclude_allergens, with the same rules as /api/recipes.

ParameterTypeDescription
iduuidRequiredSource recipe UUID
limitintegerMax results (default 5, max 20)
Example
curl -X GET "https://api.foodashi.com/api/similar?id=3f8a1c2e-9b4d-4e6f-8a2b-1c3d5e7f9a0b" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-cooking-method Indie+ 1 credit

Browse by Cooking Method

Find recipes by cooking technique such as grilling, baking, stir-frying, or slow cooking.

ParameterTypeDescription
methodstringRequiredCooking method (e.g., "grilling", "baking", "stir-frying")
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/by-cooking-method?method=grilling" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-equipment Indie+ 1 credit

Browse by Equipment

Find recipes that use specific kitchen equipment like air fryer, slow cooker, or wok.

ParameterTypeDescription
equipmentstringRequiredEquipment name (e.g., "oven", "air fryer", "slow cooker")
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/by-equipment?equipment=air+fryer" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-occasion Indie+ 1 credit

Browse by Occasion

Find recipes perfect for holidays and events like Christmas, Thanksgiving, BBQ parties, or date night.

ParameterTypeDescription
occasionstringRequiredOccasion name (e.g., "Christmas", "BBQ", "Date Night")
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/by-occasion?occasion=Christmas" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-season Indie+ 1 credit

Browse by Season

Find seasonal recipes for a given time of year. Returns recipes whose seasons array contains the requested season OR Year-Round — so year-round dishes surface in every season filter. See browse conventions for full details.

ParameterTypeDescription
seasonstringRequiredOne of: Spring, Summer, Fall (or alias Autumn), Winter, Year-Round. Case-insensitive.
randombooleanShuffle results — see browse conventions. Aliases: sort=random, shuffle=true.
pageintegerPage number (default: 1).
limitintegerResults per page (default: 20, max: 100).
Example — stable pagination
curl -X GET "https://api.foodashi.com/api/recipes/by-season?season=Spring&limit=20" \
  -H "X-Api-Key: YOUR_API_KEY"
Example — random sample
curl -X GET "https://api.foodashi.com/api/recipes/by-season?season=Spring&random=true&limit=10" \
  -H "X-Api-Key: YOUR_API_KEY"

# Each request returns a different 10 — fresh shuffle every time.
GET /api/recipes/by-nutrients Pro+ 3 credits

Browse by Nutrients

Filter recipes by nutrient ranges. Find high-protein, low-calorie, or custom macro recipes.

ParameterTypeDescription
minCaloriesnumberMinimum calories per serving
maxCaloriesnumberMaximum calories per serving
minProteinnumberMinimum protein (g) per serving
maxProteinnumberMaximum protein (g) per serving
minCarbsnumberMinimum carbs (g) per serving
maxCarbsnumberMaximum carbs (g) per serving
minFatnumberMinimum fat (g) per serving
maxFatnumberMaximum fat (g) per serving
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/by-nutrients?minProtein=25&maxCalories=500" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/by-ingredients Indie+ 2 credits

Browse by Ingredients

Find recipes that contain (or avoid) specific ingredients. Just send ingredient names — no need to look up UUIDs first. Powers "what’s in my fridge", allergen-avoidance, and pantry-based recipe discovery.

When to use this vs /api/ingredients/:id/recipes

Use this endpoint when you have an ingredient name (typical case — user types into a search box). Use /api/ingredients/:id/recipes only when you already have a specific canonical UUID from the autocomplete endpoint and want recipes that link to that exact entry.

ParameterTypeDescription
includestringRequired*Comma-separated ingredient names to include. Each term is matched independently. Multi-term acts as AND — recipes must contain all listed terms. Examples: chicken, chicken,rice, red onion,garlic.
excludestringComma-separated ingredient names to exclude. Every published recipe that holds any listed term is left out, however many there are, matched by the same rules as include (a contained word, so exclude=egg also leaves out eggplant). Example: nuts,dairy.
randombooleanShuffle results — see browse conventions.
pageintegerPage number (default: 1).
limitintegerResults per page (default: 20, max: 100).

* At least one of include or exclude is required.

Matching rules — no surprises

  • • Case-insensitive: Red Onion, red onion, RED ONION all match identically.
  • • Whitespace-normalized: red  onion (extra spaces) matches the same as red onion.
  • • Plural-tolerant: onion = onions, tomato = tomatoes, cherry = cherries. No need to guess what form the catalogue uses.
  • • Substring match: chicken matches "chicken breast", "ground chicken", "chicken thigh", etc. To be more specific, use a longer phrase like chicken breast.
  • • Typo-intolerant: red onon returns 0. For fuzzy/typo matching, hit /api/ingredients/autocomplete first and pass the corrected name.
  • • Resolver-aware: even when the catalogue stores a recipe’s ingredient as generic ("Onions, raw") rather than the specific variant ("Red Onions"), this endpoint still finds recipes that mention red onion in their original ingredient text. You get the result you expect without having to know about internal canonical IDs.
Example 1 — single ingredient
curl -X GET "https://api.foodashi.com/api/recipes/by-ingredients?include=red%20onion&limit=10" \
  -H "X-Api-Key: YOUR_API_KEY"
Example 2 — intersection (must contain BOTH)
curl -X GET "https://api.foodashi.com/api/recipes/by-ingredients?include=chicken,rice&limit=20" \
  -H "X-Api-Key: YOUR_API_KEY"
Example 3 — pantry-aware (include + exclude)
curl -X GET "https://api.foodashi.com/api/recipes/by-ingredients?include=chicken,rice&exclude=nuts,dairy" \
  -H "X-Api-Key: YOUR_API_KEY"
Example Response (truncated)
{
  "recipes": [
    {
      "id": "03905874-4035-4754-9418-13c687d7f429",
      "title": "আলু ভর্তা",
      "title_english": "Mashed Potato Bhorta",
      "image_url": "https://.../recipe-...-1776634763681.png",
      "cuisine": "Bangladeshi",
      "cuisine_code": "BD",
      "total_time_minutes": 22,
      "difficulty": "Easy",
      "servings": 4,
      "dietary_tags": ["Vegan", "Gluten-Free", "Nut-Free", "Soy-Free"],
      "tags": ["comfort-food", "dinner", "side-dish"],
      "published_at": "2026-05-06T11:33:35.731+00:00"
    }
  ],
  "filter": {
    "include": ["red onion"],
    "exclude": []
  },
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 10,
    "total_pages": 1
  }
}

Error responses

StatusBodyWhen
400{"error":"At least one of include or exclude parameter required"}Neither include nor exclude provided.
400{"error":"Maximum 10 ingredients per include/exclude list"}Too many comma-separated terms.
200{"recipes":[],"pagination":{"total":0,...}}No matches. Empty result, not an error.
503{"error":"...","code":"service_unavailable","retryable":true}An ingredient term could not be read. Retry; a page that ignored the term is never served.
GET /api/recipes/:id/nutrition Indie+ 2 credits

Recipe Nutrition

Get a full nutrition breakdown for a recipe, computed live from its ingredients. Includes macros, vitamins, and minerals per serving.

ParameterTypeDescription
:iduuidRequiredRecipe UUID
Example
curl -X GET "https://api.foodashi.com/api/recipes/{id}/nutrition" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/:id/allergens Indie+ 1 credit

Recipe Allergens

Allergen declaration covering all 14 EU-regulated allergens, hidden allergen sources, and cross-contamination warnings.

Example
curl -X GET "https://api.foodashi.com/api/recipes/{id}/allergens" \
  -H "X-Api-Key: YOUR_API_KEY"

allergen_declaration has the same shape as on the full recipe: framework, note and declaration, an object with contains, may_contain (each with its reason) and hidden_sources, or null. Here hidden_sources leaves out ingredients allergen_sources already names.

GET /api/recipes/:id/beverages Indie+ 1 credit

Beverage Pairing

AI-generated beverage pairing suggestions including wine, beer, cocktails, and non-alcoholic options.

Example
curl -X GET "https://api.foodashi.com/api/recipes/{id}/beverages" \
  -H "X-Api-Key: YOUR_API_KEY"

beverage_pairing carries six lists of strings, each always present (empty when there is nothing of that kind): wine, beer, cocktails, non_alcoholic, spirits and recommendations. A recipe without a pairing returns null.

beverage_pairing is a paid field (Indie plan and above). If it is ever served locked, it is the locked marker and note reads “Beverage pairings are included from the Indie plan.” In the Test Kitchen the body also carries "field_plans": {"beverage_pairing": "indie"}.

GET /api/recipes/:id/scale Indie+ 1 credit

Scale Servings

Recalculate all ingredient quantities for a different number of servings.

ParameterTypeDescription
:iduuidRequiredRecipe UUID
servingsintegerRequiredTarget number of servings (1-100)
Example
curl -X GET "https://api.foodashi.com/api/recipes/{id}/scale?servings=8" \
  -H "X-Api-Key: YOUR_API_KEY"

Each line carries original_quantity and scaled_quantity (numbers, or null when the line has no usable amount), the edible grams the nutrition scales with (original_gram_weight, scaled_gram_weight), scaled_purchase_gram_weight, the scaled mass to buy (bone-in, shell-on, undrained; equal to scaled_gram_weight when nothing is removed before eating), and text, the scaled line as a cook reads it.

GET /api/recipes/:id/taste Pro+ 3 credits

Taste Profile

6-axis taste profile rated 1-10: sweetness, saltiness, sourness, bitterness, savoriness, and spiciness.

Example
curl -X GET "https://api.foodashi.com/api/recipes/{id}/taste" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/:id/sustainability Pro+ 3 credits

Sustainability

The recipe's climate footprint: kg CO2 equivalent per serving and per recipe, estimated from each ingredient's weight and a climate factor for its food class. Also the plant-based share of the recipe's weight, the ingredients that contribute most, and how much of the recipe the estimate covers. No AI is involved: the same recipe always gives the same number.

  • Scope: ingredients from farm to consumer, packaging and transport included; home cooking energy excluded. An estimate for comparing dishes, not a certified label.
  • coverage: the share of the recipe's weight (water excluded) that has a climate factor. An ingredient we cannot place is listed in uncovered_ingredients and never guessed.
  • food_class: the food class each top contributor was costed as, a readable label such as beef, cheese, chocolate or milk or white chocolate. Milk and white chocolate count as animal-based in plant_based_share.
  • Source: climate factors from ADEME AGRIBALYSE v3.2 (see Data Sources).
Example
curl -X GET "https://api.foodashi.com/api/recipes/{id}/sustainability" \
  -H "X-Api-Key: YOUR_API_KEY"
Response
{
  "id": "…", "title": "Bánh tôm", "title_english": "Vietnamese Fried Shrimp and Pork Cakes",
  "sustainability": {
    "co2e_kg_per_serving": 0.49, "co2e_kg_total": 1.96, "servings": 4,
    "plant_based_share": 0.59, "coverage": 1,
    "top_contributors": [
      { "ingredient": "shrimp", "food_class": "shrimp, crab or lobster", "co2e_kg": 1.33, "share": 0.68 }
    ],
    "uncovered_ingredients": [],
    "scope": "Ingredients from farm to consumer, packaging and transport included; home cooking energy excluded.",
    "method": "Estimate: each ingredient's weight times a climate factor for its food class …"
  }
}
GET /api/recipes/:id/medical Pro+ 3 credits

Medical Cautions

Medical caution flags for conditions like diabetes, hypertension, gout, and kidney disease.

Example
curl -X GET "https://api.foodashi.com/api/recipes/{id}/medical" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/recipes/compare Pro+ 4 credits

Compare Recipes

Side-by-side nutritional comparison of 2-5 recipes.

ParameterTypeDescription
idsstringRequiredComma-separated recipe UUIDs (2-5 IDs)
Example
curl -X GET "https://api.foodashi.com/api/recipes/compare?ids=uuid1,uuid2" \
  -H "X-Api-Key: YOUR_API_KEY"
POST /api/v1/recipes/:id/reports Every plan 0 credits

Report a Recipe

Let the people using your app tell us when a recipe looks wrong. Reporting is free on every plan, Hobby included: it costs 0 credits and still works when your key is over its monthly quota. Reports of a wrong allergen or a wrong diet tag are safety reports and alert the Foodashi team straight away, so the correction reaches every app that shows the recipe.

The unversioned path /api/recipes/:id/reports is the same endpoint. Send reports from your server like every other call: your API key never belongs in client-side code.

Request body (JSON)

FieldTypeDescription
:id RequireduuidThe recipe UUID, in the path. It must be a published recipe, or the answer is 404 recipe_not_found.
reasons Requiredstring[]One or more of the reasons below (multi-select). A repeated reason counts once.
commentstringOptional, at most 500 characters. Links are removed. Required when reasons includes other (a comment that is only a link counts as empty).
end_user_refstringOptional. Your own opaque id for the end user who reported, 1 to 64 characters of A-Z a-z 0-9 _ -. Never an email address.

No other field is accepted: an unknown field returns 400 invalid_report naming it.

Reasons

ReasonUse it when
allergen_wrongAn allergen is missing or listed wrongly. Safety report.
diet_tag_wrongA diet tag such as Vegan or Gluten-Free does not fit the recipe. Safety report.
ingredient_wrongAn ingredient or a quantity is wrong or missing.
instructions_wrongA step is wrong, missing or unclear.
time_wrongThe prep, cook or total time is wrong.
nutrition_wrongA nutrition value looks wrong.
title_or_image_wrongThe title or the photo does not match the dish.
not_a_real_dishThe dish does not exist, or is not what it claims to be.
inappropriateOffensive or unsuitable content.
otherAnything else. A comment is required.

Limits and duplicates

  • • Each API key can file 20 reports per hour and 200 per 24 hours. Over either limit the answer is 429 report_limit_exceeded with a Retry-After header.
  • • The same key reporting the same recipe again for at least one of the same reasons within 24 hours gets the existing report back (200, "duplicate": true). Nothing new is stored and it does not count toward the limits, so a double tap in your app is harmless.
  • • Reports never use your monthly credits, and they keep working when your key is over its monthly quota.
Example
curl -X POST "https://api.foodashi.com/api/v1/recipes/b1a2c3d4-e5f6-7890-abcd-ef1234567890/reports" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reasons": ["allergen_wrong"], "comment": "The sauce uses fish sauce but Fish is not listed.", "end_user_ref": "usr_7f3a92"}'

Responses

StatusCodeMeaning
202 Report received and stored: {"report_id", "status": "received", "duplicate": false}.
200 A duplicate of a report this key filed in the last 24 hours: the existing report_id with "duplicate": true.
400invalid_reportThe body is not valid. field names the field at fault and message says why; a reason problem also returns accepted_reasons.
401missing_api_key, invalid_api_keyNo API key, or an unknown one.
403customer_key_requiredThe request used a server credential rather than a customer API key. Reports are filed and limited per customer key.
404recipe_not_foundNo published recipe has this id.
429report_limit_exceededThis key reached 20 reports in an hour or 200 in 24 hours. window is "hour" or "day", limit is the limit reached, and retry_after (also the Retry-After header) is the wait in seconds.
500report_not_savedThe report could not be stored right now. Retry later.
202 Accepted
{
  "report_id": "5d0c7e8a-1f2b-4c3d-9e4f-6a7b8c9d0e1f",
  "status": "received",
  "duplicate": false
}
200 OK (duplicate)
{
  "report_id": "5d0c7e8a-1f2b-4c3d-9e4f-6a7b8c9d0e1f",
  "status": "received",
  "duplicate": true
}
400 Bad Request
{
  "error": "Invalid report",
  "code": "invalid_report",
  "field": "comment",
  "message": "comment is required when reasons includes 'other' ..."
}
429 Too Many Requests
{
  "error": "Report limit reached",
  "code": "report_limit_exceeded",
  "message": "This API key reached its limit of 20 reports per hour ...",
  "window": "hour",
  "limit": 20,
  "retry_after": 1260
}
Privacy. end_user_ref is your own opaque id for the person who reported, such as your internal user id, so you can match a follow-up to your user. It accepts only letters, digits, _ and -, so it can never hold an email address; never send a name, email or phone number in any form. Do not put personal data in comment either: ask your users to describe what is wrong with the recipe, not anything about themselves.

Ingredients API — which endpoint do I use?

Foodashi exposes several ingredient endpoints. Pick by use case:

I want to…EndpointWhy
Find recipes that use a specific ingredient (typed by user) /api/recipes/by-ingredients?include=<name> Single call. Handles case, plural, whitespace, generic-vs-variant collapse. Default choice for search bars.
Power a typeahead/autocomplete UI /api/ingredients/autocomplete?q=<prefix> Fast prefix + substring search. Quality-ranked. Returns UUIDs for follow-up calls.
Get nutrition/details for a specific ingredient /api/ingredients/:id Full nutrition breakdown + portions. Requires UUID from autocomplete.
Get recipes that link to one exact canonical UUID /api/ingredients/:id/recipes Use only when you already have the UUID. For name lookup, see the top row.
Find ingredients in a food group (Produce, Dairy, …) /api/ingredients/by-food-group?group=<name> Browse by category.
Convert units (cups ↔ grams) for an ingredient /api/ingredients/:id/convert Uses ingredient-specific portion weights.

3-minute quick start

curl "https://api.foodashi.com/api/recipes/by-ingredients?include=red%20onion&limit=10" \
  -H "X-Api-Key: YOUR_API_KEY"

That’s it. One call, name → recipes. No UUID dance required.

GET /api/ingredients/autocomplete Hobby+ 1 credit

Ingredient Autocomplete

Fast prefix & substring autocomplete for ingredient search bars. Returns canonical name, UUID, food group, category, and type. Quality-ranked so the most authoritative match comes first.

Tip

You usually don’t need to call autocomplete + then a recipe lookup. /api/recipes/by-ingredients?include=<name> handles the name → recipe lookup in a single call with built-in case & plural tolerance. Use autocomplete only when you need to surface a typeahead UI to the user.

ParameterTypeDescription
qstringRequiredSearch query (min 2 chars).
limitintegerMax results (default: 10, max: 20).
Example
curl -X GET "https://api.foodashi.com/api/ingredients/autocomplete?q=red%20onion" \
  -H "X-Api-Key: YOUR_API_KEY"
Example Response
{
  "results": [
    {
      "id": "d642a69d-3c98-4c55-83a5-f231cde9eebd",
      "name": "Red Onion",
      "food_group": "11",
      "category": "Produce",
      "ingredient_type": "raw"
    },
    {
      "id": "f67dbb93-479b-4ea1-8a50-d6dc2cc33771",
      "name": "Red Onions",
      "food_group": "11",
      "category": "Produce",
      "ingredient_type": "raw"
    }
  ],
  "query": "red onion",
  "count": 2
}
GET /api/ingredients/food-groups Hobby+ 1 credit

List Food Groups

Get all food groups with ingredient counts. Useful for building category navigation.

Example
curl -X GET "https://api.foodashi.com/api/ingredients/food-groups" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/ingredients/:id Indie+ 1 credit

Ingredient Details

Get detailed nutrition information for a specific ingredient including macros, vitamins, minerals, and available portion sizes.

ParameterTypeDescription
:iduuidRequiredIngredient UUID from search results
Example Response
{
  "id": "abc123-def456...",
  "name": "Chicken breast, raw",
  "food_group": "Poultry Products",
  "nutrition_per_100g": {
    "calories": 165,
    "protein": 31,
    "fat": 3.6,
    "carbohydrates": 0
  },
  "portions": [
    { "unit": "breast", "grams": 174 }
  ],
  "source": "Blended: USDA SR Legacy + CIQUAL (France)",
  "license": "Multiple (see sources)",
  "license_url": null,
  "attribution_required": true,
  "sources": [
    { "name": "USDA SR Legacy", "license": "CC0-1.0 (U.S. public domain)", "license_url": "https://creativecommons.org/publicdomain/zero/1.0/", "attribution": "...", "source_url": "https://fdc.nal.usda.gov" },
    { "name": "CIQUAL (France)", "license": "Licence Ouverte / Open Licence (ANSES)", "license_url": "...", "attribution": "...", "source_url": "https://ciqual.anses.fr" }
  ]
}
Provenance fieldTypeDescription
sourcestringWhere the served values came from, e.g. "USDA SR Legacy". When several databases contribute it reads "Blended: A + B".
licensestringThe licence of those values, or "Multiple (see sources)" for a blend.
license_urlstringnullThe licence text; null for a blend (each source has its own).
attribution_requiredbooleantrue when at least one source asks for a credit when you show its data.
sourcesarrayOne entry per source database: name, license, license_url, attribution (the credit line to show) and source_url.

/api/ingredients/search results carry the same five fields. Open Food Facts product rows are served only by /api/barcode, with its ODbL notice. Rows from the Indian Nutrient Databank (INDB) are never served: every by-id ingredient endpoint answers 404 for them, as for an unknown id.

In nutrition_per_100g, a value the source does not state is null, never 0; a measured 0 stays 0.

GET /api/barcode/:barcode Indie+ 1 credit

Barcode Lookup

Look up a packaged product by its UPC/EAN barcode and get its name, brand, and per-100g nutrition (energy, protein, fat, carbs, sodium, fiber, saturated fat, sugars), normalized to Foodashi's nutrient model. Data sourced from Open Food Facts under the ODbL; community-sourced nutrition is flagged with confidence 0.7. Results are cached. Every response carries the credit, the licence and a link to the product page (see Data licensing below).

ParameterTypeDescription
:barcodestringRequiredGTIN-8, UPC-A (12 digits), EAN-13 or GTIN-14, with a valid check digit
Example
curl -X GET "https://api.foodashi.com/api/barcode/3017620422003" \
  -H "X-Api-Key: YOUR_API_KEY"
Example Response
{
  "barcode": "3017620422003",
  "product_name": "Nutella",
  "brand": "Ferrero, Nutella, Yum yum",
  "country": "france",
  "nutrition": {
    "energy_kcal": 539,
    "protein": 6.3,
    "total_fat": 30.9,
    "carbohydrate": 57.5,
    "sodium": 0.0428,
    "fiber": null,
    "saturated_fat": 10.6,
    "sugars_total": 56.3
  },
  "nutrition_confidence": 0.7,
  "nutrition_gaps": ["fiber"],
  "matched_canonical_id": null,
  "data_origin": "openfoodfacts_live",
  "source": "openfoodfacts",
  "attribution": "Data from Open Food Facts (ODbL)",
  "attribution_url": "https://world.openfoodfacts.org",
  "license": "ODbL-1.0",
  "license_url": "https://opendatacommons.org/licenses/odbl/1-0/",
  "product_url": "https://world.openfoodfacts.org/product/3017620422003",
  "cached_at": "2026-06-25T...",
  "image_url": "https://images.openfoodfacts.org/images/products/301/762/042/2003/front_en.879.400.jpg",
  "image_small_url": "https://images.openfoodfacts.org/images/products/301/762/042/2003/front_en.879.200.jpg",
  "image_license": "CC BY-SA 3.0",
  "image_attribution": "Open Food Facts",
  "image_source": "https://world.openfoodfacts.org/product/3017620422003"
}

Nutrition is per 100 g, with sodium in grams per 100 g. A nutrient the product data does not state is null and is named in nutrition_gaps, never 0; a stated 0 stays 0.

Image fieldTypeDescription
image_urlstringnullOpen Food Facts product photo (front of pack, ~400px), served unmodified from images.openfoodfacts.org.
image_small_urlstringnull200px thumbnail variant of image_url.
image_licensestringnullAlways "CC BY-SA 3.0" when an image exists, otherwise null.
image_attributionstringnullAlways "Open Food Facts" when an image exists, otherwise null.
image_sourcestringnullOpen Food Facts product page URL to link back to (e.g. https://world.openfoodfacts.org/product/{barcode}).

Image licensing. All five image fields are null together when the product has no photo. Product images are Open Food Facts photos under CC BY-SA 3.0 (a separate license from the ODbL nutrition data). If your app displays the image you must attribute "Open Food Facts", keep the CC BY-SA 3.0 credit, link back (the image_attribution, image_license, and image_source fields carry exactly what you need), and show the image unmodified.

Licence fieldTypeDescription
sourcestringAlways "openfoodfacts".
attributionstringThe credit line: "Data from Open Food Facts (ODbL)".
attribution_urlstringOpen Food Facts home page, to link the credit to.
licensestringLicence of the product data: "ODbL-1.0".
license_urlstringThe licence text.
product_urlstringThis product’s page on Open Food Facts.
data_originstring"openfoodfacts_export" (served from our local copy of the Open Food Facts export) or "openfoodfacts_live" (fetched from Open Food Facts on a local miss).

Data licensing. Product data is from Open Food Facts under the Open Database License (ODbL). If your app shows or redistributes it, credit Open Food Facts and keep the licence; the attribution, license, license_url, attribution_url and product_url fields carry what you need. Local hits (data_origin "openfoodfacts_export") carry no brand or photo: brand, country, quantity and the five image fields are null.

Errors. A code that is not a GTIN-8, UPC-A (12 digits), EAN-13 or GTIN-14 with a valid check digit returns 400 invalid_barcode before any lookup is made. An unknown product returns 404. When a lookup needs the live Open Food Facts service and its rate limit is reached, the answer is 503 with code upstream_rate_limited and a Retry-After header in seconds; retry after it.

GET /api/ingredients/:id/convert Indie+ 1 credit

Unit Conversion

Convert between different units for a specific ingredient using real portion data.

ParameterTypeDescription
:iduuidRequiredIngredient UUID
amountnumberRequiredAmount to convert
from_unitstringRequiredSource unit (e.g., "cup", "tbsp")
to_unitstringRequiredTarget unit (e.g., "g", "ml")
Example
curl -X GET "https://api.foodashi.com/api/ingredients/{id}/convert?amount=2&from_unit=cup&to_unit=g" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/ingredients/:id/substitutes Indie+ 1 credit

Ingredient Substitutes

Find nutritionally similar substitutes for an ingredient based on food group and macro profile.

ParameterTypeDescription
:iduuidRequiredIngredient UUID from search results
Example
curl -X GET "https://api.foodashi.com/api/ingredients/{id}/substitutes" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/ingredients/:id/recipes Indie+ 1 credit

Recipes Using Ingredient (by UUID)

Find all published recipes that use the canonical ingredient identified by UUID. The UUID typically comes from /api/ingredients/autocomplete or /api/ingredients/search.

For a name-based lookup, prefer /api/recipes/by-ingredients

This endpoint matches by exact canonical UUID. If you have an ingredient name (e.g. "red onion"), call /api/recipes/by-ingredients?include=red%20onion instead — it handles case, plural, whitespace, and resolves variants automatically.

ParameterTypeDescription
:iduuidRequiredIngredient canonical UUID (from autocomplete or search).
randombooleanShuffle the matched recipes — see browse conventions.
pageintegerPage number (default: 1).
limitintegerResults per page (default: 20, max: 50).

Smart text fallback (2026-05-10)

If 0 recipes link to the exact canonical UUID, this endpoint automatically falls back to a text search using the canonical’s display name. So you get consistent results even when the ingredient resolver collapsed a variant (e.g. recipes mentioning "red onion" linking to generic "Onions, raw"). Hidden from the API consumer — you just see the right recipes.

Example
curl -X GET "https://api.foodashi.com/api/ingredients/d642a69d-3c98-4c55-83a5-f231cde9eebd/recipes?limit=10" \
  -H "X-Api-Key: YOUR_API_KEY"
Example Response
{
  "ingredient_id": "d642a69d-3c98-4c55-83a5-f231cde9eebd",
  "recipes": [
    {
      "id": "eb0b3a12-8394-45ac-aa4c-d42f13e09ce5",
      "title": "වම්බටු මෝජු",
      "title_english": "Sri Lankan Eggplant Moju",
      "image_url": "https://.../recipe-...-1776635175073.png",
      "cuisine": "Sri Lankan",
      "total_time_minutes": 66,
      "difficulty": "Medium",
      "servings": 6,
      "dietary_tags": ["Vegan", "Gluten-Free"]
    }
  ],
  "pagination": { "page": 1, "limit": 10, "total": 10, "total_pages": 1 }
}

Behavior notes

  • • If 0 direct matches exist on the canonical link, the endpoint falls back to a text search using the canonical’s display name. You don’t need to know whether the recipe linked to the generic or specific variant — the result set is consistent.
  • • Returns 400 if :id is not a valid UUID.
  • • Returns 200 with empty recipes array when no matches (not a 404).
GET /api/ingredients/:id/allergens Indie+ 1 credit

Ingredient Allergen Check

Check which EU-14 allergens an ingredient contains or may contain.

Example
curl -X GET "https://api.foodashi.com/api/ingredients/{id}/allergens" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/ingredients/by-food-group Indie+ 1 credit

Browse by Food Group

Browse ingredients within a food group. Accepts either a friendly category name ("Produce", "Dairy", "Bakery", "Pantry") or a USDA numeric food-group code ("11" for Vegetables). Case-insensitive for names.

ParameterTypeDescription
groupstringRequiredCategory name (e.g. Produce, Dairy) OR USDA numeric code (e.g. 11). Discover available groups via /api/ingredients/food-groups.
randombooleanShuffle — see browse conventions.
pageintegerPage number (default: 1).
limitintegerResults per page (default: 20, max: 100).
Example — by category name
curl -X GET "https://api.foodashi.com/api/ingredients/by-food-group?group=Produce&limit=20" \
  -H "X-Api-Key: YOUR_API_KEY"
Example — by USDA code
curl -X GET "https://api.foodashi.com/api/ingredients/by-food-group?group=11&limit=20" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/ingredients/:id/portions Indie+ 1 credit

Ingredient Portions

Get all available portion sizes for an ingredient with gram weight equivalents.

Example
curl -X GET "https://api.foodashi.com/api/ingredients/{id}/portions" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/ingredient-substitute Hobby+ 1 credit

Quick Ingredient Substitute

Lightweight ingredient-name substitute lookup (no UUID needed). Pass an ingredient name as a query parameter; receive common substitutes from a curated lookup table. For nutritionally-accurate substitutes use /api/ingredients/:id/substitutes instead.

ParameterTypeDescription
ingredient or name or q RequiredstringIngredient name (e.g. "butter", "egg", "buttermilk"). Case-insensitive; partial matches accepted. All three parameter names are accepted — use whichever fits your code style.
Examples — all three forms work
curl -X GET "https://api.foodashi.com/api/ingredient-substitute?ingredient=butter" -H "X-Api-Key: KEY"
curl -X GET "https://api.foodashi.com/api/ingredient-substitute?name=butter"       -H "X-Api-Key: KEY"
curl -X GET "https://api.foodashi.com/api/ingredient-substitute?q=butter"          -H "X-Api-Key: KEY"
POST /api/recipes/analyze Pro+ 5 credits

Analyze Existing Recipe (by ID)

Run deep analysis on a specific recipe in our database — returns its full classification (meal_types, dish_types, occasions), nutrition breakdown, allergen detection, dietary tag confidence, and NutriMetric score. Use this to enrich recipe metadata in your app without re-running the full /api/analyze/text endpoint.

Body FieldTypeDescription
recipe_id RequireduuidRecipe UUID from /api/recipes or /api/search.
Example
curl -X POST "https://api.foodashi.com/api/recipes/analyze" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"recipe_id": "a1b2c3d4-e5f6-..."}'

Response

Response
{
  "recipe_id": "3f8a1c2e-9b4d-4e6f-8a2b-1c3d5e7f9a0b",
  "title": "Pot-au-feu",
  "title_english": "Beef and Vegetable Stew",
  "source": "stored_analysis",
  "classification": {
    "cuisine": "French",
    "meal_types": ["Dinner", "Main Course"],
    "dish_types": ["Stew"],
    "occasions": ["Family Dinner"],
    "seasons": ["Winter"],
    "cooking_methods": ["Simmering"],
    "difficulty": "Medium",
    "protein_source": "Beef"
  },
  "nutrition": { /* same nutrition object as /api/recipes/details */ },
  "allergens": ["Celery"],
  "allergen_declaration": { /* EU 1169/2011 declaration */ },
  "dietary_tags": ["Dairy-Free"],
  "dietary_tag_confidence": { "Dairy-Free": 0.95 },
  "nutrimetric": { /* score and grade */ }
}

dietary_tag_confidence maps each tag to a confidence from 0 to 1. To analyse an ad hoc ingredient list instead, send {"ingredients": [{"ingredient_id": "<canonical ingredient UUID>", "amount": 250, "unit": "g"}], "servings": 4} (resolve names to ids with /api/ingredients/search). Send one body or the other, not both.

The ingredients body weighs masses only: unit is g, kg, mg, lb or oz, or a spelling of one such as grams or ounces (case-insensitive), and amount is a number from 0. A volume or piece unit (cup, tbsp, piece) is refused with a 400 invalid_parameter that lists supported_units: send grams, or use /api/nutrition/calculate, which weighs volumes and pieces from the food's own data. In the breakdown, a nutrient a food does not state is null on its line and in every total it enters, never 0.

POST /api/ingredients/batch Pro+ 5 credits

Batch Ingredient Lookup

Look up multiple ingredients at once. Much faster than individual searches for recipes.

Request Body
{
  "ingredients": ["chicken", "rice", "tomato"]
}
Example
curl -X POST "https://api.foodashi.com/api/ingredients/batch" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ingredients": ["chicken", "rice", "tomato"]}'

Or pass {"ids": ["<canonical ingredient UUID>", ...]} (max 50) to look up by id; results come back in your order with match_type "id". Names are also limited to 50 per call. Each found result carries ingredient.nutrition_per_100g, the values per 100 g by nutrient key; a value the source does not state is null, never 0.

GET /api/ingredients/by-nutrient Pro+ 3 credits

Ingredients by Nutrient

Find ingredients high or low in a specific nutrient. Great for meal planning and dietary goals.

ParameterTypeDescription
nutrientstringRequiredNutrient name (e.g., "protein", "iron", "vitamin_c")
minnumberMinimum amount per 100g
maxnumberMaximum amount per 100g
limitintegerResults per page (default: 20, max: 100)
Example
curl -X GET "https://api.foodashi.com/api/ingredients/by-nutrient?nutrient=protein&min=20" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/ingredients/compare Pro+ 2 credits

Compare Ingredients

Side-by-side nutritional comparison of 2-5 ingredients per 100g.

ParameterTypeDescription
idsstringRequiredComma-separated ingredient UUIDs (2-5 IDs)
Example
curl -X GET "https://api.foodashi.com/api/ingredients/compare?ids=uuid1,uuid2" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/nutrition/nutrients Hobby+ 1 credit

Nutrient List

Get all tracked nutrients with their units and categories (macros, vitamins, minerals, etc.).

Example
curl -X GET "https://api.foodashi.com/api/nutrition/nutrients" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/nutrition/daily-values Hobby+ 1 credit

Daily Reference Values

FDA Daily Values for 31 nutrients, based on a 2,000 calorie diet (21 CFR 101.9, the current Nutrition Facts rule). A nutrient with no Daily Value, such as total sugars or trans fat, returns value: null with a note. The 50 g sugar reference applies to added sugars only, so recipe responses report daily_value_percent.sugars_total_g as null.

Example
curl -X GET "https://api.foodashi.com/api/nutrition/daily-values" \
  -H "X-Api-Key: YOUR_API_KEY"
POST /api/nutrition/daily-needs Indie+ 3 credits

Personalized Daily Needs

Estimate a person's daily calorie and macro targets (BMR, TDEE, protein/fat/carbohydrate) using the Mifflin-St Jeor equation. Deterministic and free of AI. Unlike Daily Values (the fixed FDA labeling reference), this personalizes to the individual. All inputs are optional: supply all five core inputs (age, weight, height, sex, activity level) for a personalized result; if any are missing, sensible defaults are applied, the result is flagged estimated, and each defaulted field is named in assumptions. This is always an estimate from a population formula, not medical or dietary advice.

Body FieldTypeDescription
ageintegerAge in years (1–120). Optional.
weight_kgnumberBody weight in kilograms (2–500). Optional. Use weight_lb for pounds instead.
height_cmnumberHeight in centimetres (50–260). Optional. Use height_in for inches instead.
sexstring"male", "female", or "unspecified". Optional.
activity_levelstring"sedentary", "light", "moderate", "active", or "very_active". Optional.
goalstring"maintain", "lose", or "gain" (default "maintain"). Optional.
Example
curl -X POST "https://api.foodashi.com/api/nutrition/daily-needs" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"age":30,"weight_kg":75,"height_cm":180,"sex":"male","activity_level":"moderate","goal":"maintain"}'
Example Response
{
  "precision": "personalized",
  "estimated": false,
  "bmr_kcal": 1730,
  "tdee_kcal": 2682,
  "target_kcal": 2682,
  "goal": "maintain",
  "macros": { "protein_g": 120, "fat_g": 89, "carbohydrate_g": 350 },
  "targets": { "fiber_g": 38, "saturated_fat_max_g": 30, "added_sugars_max_g": 67, "sodium_max_mg": 2300 },
  "targets_note": "Fiber is a daily minimum (14 g per 1,000 kcal). Saturated fat and added sugars are upper limits (10% of calories). Sodium is the fixed FDA upper reference of 2,300 mg/day and is NOT personalized. For the full vitamin and mineral reference table, use GET /api/nutrition/daily-values.",
  "inputs_used": { "age": 30, "weight_kg": 75, "height_cm": 180, "sex": "male", "activity_level": "moderate", "activity_label": "Moderate exercise 3-5 days/week" },
  "assumptions": [],
  "method": "Mifflin-St Jeor BMR x activity factor. Protein 1.6 g/kg, fat 30% of calories, carbohydrate remainder.",
  "disclaimer": "Estimate only, not medical or dietary advice. ..."
}
Response fieldTypeDescription
precisionstring"personalized" when all five core inputs were supplied, otherwise "estimated".
estimatedbooleantrue when one or more inputs were defaulted. The output is always an estimate regardless.
bmr_kcalintegerBasal metabolic rate from the Mifflin-St Jeor equation.
tdee_kcalintegerTotal daily energy expenditure (BMR × activity factor).
target_kcalintegerCalorie target after applying the goal adjustment.
macrosobjectDaily protein, fat, and carbohydrate targets in grams.
targets.fiber_gintegerDaily fiber minimum in grams (eat at least this; 14 g per 1,000 kcal).
targets.saturated_fat_max_gintegerSaturated fat upper limit in grams (stay under; ~10% of calories).
targets.added_sugars_max_gintegerAdded sugars upper limit in grams (stay under; ~10% of calories).
targets.sodium_max_mgintegerSodium upper limit in milligrams. Fixed FDA upper reference (2,300 mg/day); not personalized.
targets_notestringPlain-language explanation that fiber is a minimum, saturated fat and added sugars are limits, and sodium is the fixed FDA reference (not personalized).
inputs_usedobjectThe effective inputs (including any defaults) used for the calculation, plus a human-readable activity_label.
assumptionsarrayOne entry per defaulted field, naming the field and the value assumed. Empty when fully personalized.
disclaimerstringAlways present. This is an estimate, not medical or dietary advice.

Inputs outside what the equation describes are refused with a 400, never answered with a negative or empty target: a combination whose BMR is not positive, or whose protein (1.6 g per kg) and fat (30% of calories) already exceed the calorie target. activity_level must be one of sedentary, light, moderate, active or very_active.

POST /api/nutrition/calculate Indie+ 5 credits

Calculate Nutrition

Send a structured ingredient list and get complete nutrition back. Every name is resolved against our canonical ingredient database, then run through the same nutrition engine that powers the recipe catalog, so you get per-serving, per-100g and whole-recipe figures plus a NutriMetric grade. It makes no AI calls, which means it is fast, repeatable, and costs 5 rather than 175.

Which endpoint do I want? Use /api/nutrition/calculate when you already know your ingredients and amounts. Use /api/analyze/text when you have unstructured recipe text that still needs parsing — it reads the method as well, so it is the better choice for prose.

Body FieldTypeDescription
ingredientsarrayRequired1 to 100 items. Each needs a name plus either grams, or amount + unit. Optional preparation (up to 200 characters), written as a recipe would: a stated state or grade picks the matching food, so {"name":"butter","grams":30,"preparation":"unsalted, softened"} is costed as unsalted butter, not salted.
servingsnumberDefaults to 1. Divides the total into per-serving figures.
stepsarrayOptional method text. When supplied, discarded cooking media are accounted for — a marinade you lift the food out of, a salt crust, confit fat, dredging flour. Without it those are counted as eaten.
titlestringOptional dish name. Helps NutriMetric pick the right category.
Example
curl -X POST "https://api.foodashi.com/api/nutrition/calculate"   -H "X-Api-Key: YOUR_API_KEY"   -H "Content-Type: application/json"   -d '{"ingredients":[{"name":"chicken breast","grams":300},{"name":"basmati rice","grams":200},{"name":"olive oil","amount":1,"unit":"tbsp"}],"servings":2}'

Response

Returns per_serving, per_100g and total nutrition, a nutrimetric grade, coverage and confidence, and an ingredients breakdown showing exactly which canonical food each name matched — so you can see why a number came out the way it did, and which items we could not match.

If no name matches a known food, or no matched food has nutrient data, the answer is 422 with code unprocessable_entity. If a nutrient read fails, the answer is a 503 with code service_unavailable (retry), never a total that counts the food as zero.

POST /api/nutrition/label Indie+ 3 credits

Nutrition Label

Generate FDA or EU format nutrition label data from custom ingredient lists. Returns structured label data with %DV calculations.

Body FieldTypeDescription
nutrition_per_servingobjectRequiredPre-computed per-serving nutrients. Keys: calories, total_fat_g, saturated_fat_g, trans_fat_g, cholesterol_mg, sodium_mg, total_carbohydrate_g, dietary_fiber_g, total_sugars_g, added_sugars_g, protein_g
serving_sizestringHuman-readable serving size, e.g. "2/3 cup (55g)"
servings_per_containerintegerServings per container/recipe
formatstring"fda" or "eu" (default: "fda")
Example
curl -X POST "https://api.foodashi.com/api/nutrition/label" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"nutrition_per_serving":{"calories":250,"total_fat_g":12,"saturated_fat_g":3,"cholesterol_mg":30,"sodium_mg":470,"total_carbohydrate_g":31,"dietary_fiber_g":2,"total_sugars_g":5,"added_sugars_g":2,"protein_g":18},"serving_size":"2/3 cup (55g)","servings_per_container":8,"format":"fda"}'
POST /api/nutrition/nutrimetric Indie+ 3 credits

NutriMetric Calculator

Calculate NutriMetric nutrition quality score (A–F grade, 0-100 scale) for custom nutrition data. Uses 4 scoring pillars: protein density, calorie density, fat balance, and sodium. Category-aware for beverages, soups, desserts, and more.

Body FieldTypeDescription
nutrition_per_100gobjectRequiredNutrients per 100g. Required: energy_kcal, protein_g, fat_g, carbohydrate_g, sodium_mg (sodium in mg). Bonus (improve score): fiber_g, saturated_fat_g, sugars_total_g. Legacy aliases accepted (calories, protein, total_fat, carbohydrate/carbs, sodium).
categorystring"main", "beverage", "soup", "salad", "dessert", or "snack" (auto-detected from nutrient profile if omitted)
Example
curl -X POST "https://api.foodashi.com/api/nutrition/nutrimetric" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"nutrition_per_100g":{"energy_kcal":190,"protein_g":12,"fat_g":8,"carbohydrate_g":15,"sodium_mg":400,"fiber_g":2,"saturated_fat_g":3,"sugars_total_g":5},"category":"main"}'
POST /api/nutrition/log Pro+ 85 credits

Natural-Language Meal Logging

Send free text describing what someone ate and get a per-item breakdown of foods with estimated grams and an 8-nutrient profile each, plus a summed total. This is an AI endpoint (one Gemini parse followed by deterministic nutrition lookup) billed at 85 credits. It is stateless: it computes and returns, it stores nothing. Portions are inferred from the text and some nutrition values are AI-estimated (flagged at nutrition_confidence 0.7, versus 1.0 for USDA values). Free and Indie developers can try it in the Test Kitchen on the trial budget. Limits: 500-character max input, 20 items max per call.

Body FieldTypeDescription
textstringRequiredFree text describing what was eaten (for example "2 scrambled eggs, a slice of whole wheat toast, and a cup of orange juice"). Max 500 characters, up to 20 items.
Example
curl -X POST "https://api.foodashi.com/api/nutrition/log" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"2 scrambled eggs, a slice of whole wheat toast, and a cup of orange juice"}'
Example Response
{
  "input": "2 scrambled eggs, a slice of whole wheat toast, and a cup of orange juice",
  "items": [
    {
      "food": "egg",
      "quantity": 2,
      "unit": "medium",
      "grams": 100,
      "matched_canonical_id": "ec721176-...",
      "matched_name": "Egg, whole, raw, fresh",
      "match_confidence": 1,
      "nutrition": { "energy_kcal": 143, "protein": 12.6, "total_fat": 9.5, "carbohydrate": 0.7, "sodium": 142, "fiber": 0, "saturated_fat": 3.1, "sugars_total": 0.4 },
      "nutrition_confidence": 1
    },
    {
      "food": "whole wheat toast",
      "quantity": 1,
      "unit": "slice",
      "grams": 30,
      "matched_name": "Whole Wheat Toast",
      "match_confidence": 1,
      "nutrition": { "energy_kcal": 102, "protein": 1.8, "total_fat": 1.2, "carbohydrate": 19.7, "sodium": 132, "fiber": 2.8, "saturated_fat": 0.3, "sugars_total": 1.7 },
      "nutrition_confidence": 1
    },
    {
      "food": "orange juice",
      "quantity": 1,
      "unit": "cup",
      "grams": 240,
      "matched_name": "Orange juice, raw",
      "match_confidence": 1,
      "nutrition": { "energy_kcal": 113, "protein": 1.6, "total_fat": 0.5, "carbohydrate": 26.4, "sodium": 2.4, "fiber": 0.5, "saturated_fat": 0.1, "sugars_total": 20.8 },
      "nutrition_confidence": 1
    }
  ],
  "total": { "energy_kcal": 358, "protein": 16, "total_fat": 11.2, "carbohydrate": 46.8, "sodium": 276.4, "fiber": 3.3, "saturated_fat": 3.5, "sugars_total": 22.9 },
  "item_count": 3,
  "unresolved": [],
  "confidence": 1,
  "disclaimer": "Portions inferred from text; nutrition is per-ingredient estimated or USDA. Stateless, nothing is stored.",
  "source": "foodashi"
}
Response fieldTypeDescription
itemsarrayOne entry per parsed food, with the parsed quantity/unit, the estimated grams, the matched canonical (matched_canonical_id, matched_name) with match_confidence (0 to 1), the per-item nutrition for that gram amount, and nutrition_confidence (1.0 USDA, 0.7 AI-estimated).
nutritionobjectThe 8 nutrients per item: energy_kcal, protein, total_fat, carbohydrate, sodium, fiber, saturated_fat, sugars_total.
totalobjectThe same 8 nutrients, summed across all items.
item_countintegerNumber of parsed items.
unresolvedarrayFoods that could not be matched, returned honestly.
confidencenumberAggregate confidence across the meal (0 to 1).

Errors. If the meal text cannot be parsed, the answer is 502 (rephrase it). If a food lookup or a nutrient read fails after the parse, the answer is 503 service_unavailable with "retryable": true, never a meal with that food counted as zero or as unmatched, and nothing is cached. The AI parse has already run, so, as for any error after AI tokens were billed, the call’s credits stay spent.

GET /api/convert Hobby+ 1 credit

Unit Converter

General-purpose unit conversion with ingredient-specific density adjustments. Supports 30+ units including cups, tablespoons, ounces, and more.

ParameterTypeDescription
amountnumberRequiredAmount to convert
fromstringRequiredSource unit (e.g., "cup", "tbsp", "oz")
tostringTarget unit (default: "g")
ingredientstringIngredient for density-adjusted conversion (e.g., "flour", "sugar")
Example
curl -X GET "https://api.foodashi.com/api/convert?amount=1&from=cup&to=g&ingredient=flour" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/allergens Hobby+ 1 credit

Allergen List

Complete list of EU 14 regulated allergens plus extended allergens, with EU regulation metadata.

Example
curl -X GET "https://api.foodashi.com/api/allergens" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/diets Hobby+ 1 credit

Diet List

All 21 dietary tags, grouped by category: lifestyle, low-carb, allergen-free, nutritional, regional and other. These are exactly the values diet= accepts.

Example
curl -X GET "https://api.foodashi.com/api/diets" \
  -H "X-Api-Key: YOUR_API_KEY"
GET /api/cuisines Hobby+ 1 credit

Cuisine List

All 80 world cuisines grouped by region: East/Southeast Asia, South & Central Asia, Middle East, North Africa, Europe, Nordic, North America, South America, Caribbean, Pacific, and Sub-Saharan Africa.

Example
curl -X GET "https://api.foodashi.com/api/cuisines" \
  -H "X-Api-Key: YOUR_API_KEY"
POST /api/analyze/text Pro+ 175 credits

Analyze Recipe Text

Extract a recipe from raw text using AI, then run the full nutrition pipeline: 8 nutrients with %DV, EU 14 allergens, dietary tags, NutriMetric scoring, and the recipe's climate footprint (sustainability, the same fields as Sustainability).

Request Body

FieldTypeDescription
text RequiredRequiredstringRaw recipe text (blog post, pasted instructions, typed). Min 20 characters.
servingsintegerOverride detected servings count.

Response Highlights

  • recipe — Extracted title, servings, ingredients with amounts/units/preparation
  • nutrition — per_serving, per_100g, per_recipe with 8 nutrients + %DV
  • allergens / may_contain — EU 14 allergen detection with sources
  • dietary_tags: from the 21 dietary tags (Vegan, Keto, Gluten-Free, etc.)
  • nutrimetric — Proprietary nutrition grade (A–F, A best)
cURL
curl -X POST "https://api.foodashi.com/api/analyze/text" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Chicken Parmesan\n\n2 chicken breasts\n1 cup breadcrumbs\n1 cup marinara\n1 cup mozzarella\n\n1. Bread chicken. 2. Fry. 3. Top with sauce and cheese. 4. Bake 375F 20 min."}'

Errors. If a nutrient read fails after the recipe is extracted, the answer is 503 service_unavailable with "retryable": true, never totals that leave a food out or count it as zero. The AI extraction has already run, so the call’s credits stay spent.

POST /api/analyze/url Pro+ 275 credits

Analyze Recipe URL

Fetch a recipe from any URL, extract it with AI, then run the full nutrition + allergen + NutriMetric pipeline, with the recipe's climate footprint (sustainability). Works with most recipe blogs and cooking sites.

Request Body

FieldTypeDescription
url RequiredRequiredstringFull URL to a recipe page (http/https).
servingsintegerOverride detected servings count.
cURL
curl -X POST "https://api.foodashi.com/api/analyze/url" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://cooking.nytimes.com/recipes/1015819-chocolate-chip-cookies"}'

Errors. 502 when the page cannot be fetched, 422 when no recipe is found on it. If a nutrient read fails after the recipe is extracted, the answer is 503 service_unavailable with "retryable": true, never totals that leave a food out or count it as zero. The AI extraction has already run, so the call’s credits stay spent.

POST /api/recognize/image Pro+ 65 credits

Recognize Dish from Photo

Upload a food photo (base64 or URL) and get dish identification with confidence score, estimated ingredients with gram weights, estimated nutrition, and matching recipes from our database.

Request Body

FieldTypeDescription
image RequiredstringBase64-encoded image (supports data URI). Max 4MB. Provide image OR image_url.
image_urlstringURL to fetch the image from (JPEG, PNG, WebP, GIF).
include_recipesbooleanInclude matching recipes from database (default: true).
max_resultsintegerMax recipe matches to return (default: 5, max: 10).
cURL
curl -X POST "https://api.foodashi.com/api/recognize/image" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"image_url": "https://example.com/pizza-photo.jpg", "max_results": 3}'

Partial answers. If the recipe lookup fails after the dish is identified, the identification is still served with matched_recipes: [], and data carries "partial": true and errors: [{"code": "service_unavailable", "field": "matched_recipes", "message": "...", "retryable": true}]. Both fields appear only then: an empty matched_recipes without them means no recipe matched.

POST /api/recognize/ingredients Pro+ 110 credits

Recognize Ingredients from Photo

Snap a photo of your fridge, pantry, or counter and get every ingredient identified with estimated quantities, canonical DB matches (for precise nutrition lookup), storage suggestions, and recipe ideas.

Request Body

FieldTypeDescription
image RequiredstringBase64-encoded image. Provide image OR image_url.
image_urlstringURL to fetch the image from (JPEG, PNG, WebP, GIF).
include_recipesbooleanInclude recipe suggestions using detected ingredients (default: true).
max_resultsintegerMax recipe suggestions (default: 5, max: 10).
cURL
curl -X POST "https://api.foodashi.com/api/recognize/ingredients" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"image_url": "https://example.com/fridge-contents.jpg"}'
POST /api/pairing/beverages Pro+ 90 credits

AI Sommelier — Beverage Pairing

Get expert beverage pairings from an AI Master Sommelier. Supports wine, beer, cocktails, spirits, and culturally-specific non-alcoholic beverages. Accepts dish names, ingredient lists, food photos, or recipe IDs.

Request Body (provide exactly one)

FieldTypeDescription
dishstringDish name (e.g., "Pad Thai", "Feijoada").
ingredientsstring[]Ingredient list — AI identifies the likely dish first.
imagestringBase64-encoded food photo. Provide image OR image_url.
image_urlstringURL to a food photo (JPEG, PNG, WebP, GIF).
recipe_idstringUUID of a published recipe in the database.

Optional Preferences

FieldTypeDescription
preferences.no_alcoholbooleanOnly return non-alcoholic beverages.
preferences.budgetstring"low", "medium", or "high" — affects price range of suggestions.
preferences.stylestring"casual" or "fine-dining" — affects formality of recommendations.

Response

Returns 5 beverage categories with specific names, reasoning, and serving details.

FieldDescription
pairings.wine[]Specific varietals with region, price range, serving temp, and alternatives.
pairings.beer[]Beer styles with category, price range, serving temp, and alternatives.
pairings.cocktails[]Culturally-relevant cocktails with base spirit and brief recipe.
pairings.spirits[]Neat pours or simple serves with serving suggestion.
pairings.non_alcoholic[]Culturally-specific beverages (Lassi, Horchata, etc.) with brief recipe.
sommelier_noteOverarching pairing philosophy for the dish.
confidence0.0–1.0 confidence score for the pairing.
cURL
curl -X POST "https://api.foodashi.com/api/pairing/beverages" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dish": "Feijoada"}'
cURL (with preferences)
curl -X POST "https://api.foodashi.com/api/pairing/beverages" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dish": "Biryani", "preferences": {"no_alcohol": true, "style": "fine-dining"}}'
POST /api/meal-plan/generate Pro+ 400 credits

Generate Meal Plan

AI-powered meal plan generator. Specify calorie targets, macro ratios, dietary restrictions, allergen exclusions, and cuisine preferences. Returns a day-by-day plan with real DB recipes (full nutrition) plus AI-generated suggestions where needed. Includes daily/weekly nutrition totals and a shopping-list-compatible format.

Request Body

FieldTypeDescription
daysintegerPlan duration, 1-14 (default: 7).
goalstringmaintain, lose_weight, gain_weight, or build_muscle.
calories_per_dayintegerOverride calorie target (auto-set by goal if omitted).
dietary_restrictionsstring[]Array of dietary tags: ["Dairy-Free", "Gluten-Free"]
allergen_exclusionsstring[]EU 14 allergens to exclude: ["Peanuts", "Tree Nuts"]
cuisine_preferencesstring[]Preferred cuisines: ["Japanese", "Italian"]
meals_per_daystring[]Meal types: ["breakfast","lunch","dinner"] (also: snack, brunch).
servingsintegerServings per meal (default: 2).
cURL
curl -X POST "https://api.foodashi.com/api/meal-plan/generate" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "days": 7,
    "goal": "lose_weight",
    "calories_per_day": 1600,
    "dietary_restrictions": ["Dairy-Free"],
    "meals_per_day": ["breakfast", "lunch", "dinner"],
    "servings": 2
  }'
POST /api/meal-plan/customize Pro+ 200 credits

Customize Meal Plan

Modify an existing meal plan: swap a specific meal with a chosen recipe, regenerate all meals for a day, or regenerate a single meal. Pass the plan object from the generate endpoint.

Request Body

FieldTypeDescription
planRequiredobjectThe plan object from /api/meal-plan/generate response.
actionRequiredstringswap, regenerate_day, or regenerate_meal.
day_indexRequiredinteger0-based day index to modify.
meal_indexinteger0-based meal index (required for swap and regenerate_meal).
swap_recipe_iduuidRecipe ID to swap in (required for swap action).
reasonstringOptional context for AI regeneration.
cURL (swap action)
curl -X POST "https://api.foodashi.com/api/meal-plan/customize" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plan": {...}, "action": "swap", "day_index": 0, "meal_index": 2, "swap_recipe_id": "uuid"}'
GET /api/meal-plan/templates Indie+ 1 credit

Meal Plan Templates

Browse 8 pre-built meal plan templates covering common goals: Balanced Weight Loss, Muscle Building, Mediterranean Heart Health, Plant-Based Week, Keto, Family Friendly, Quick Meals, and Clean Bulk.

Query Parameters

ParameterTypeDescription
goalstringFilter by goal: lose_weight, maintain, gain_weight, build_muscle.
cURL
curl -X GET "https://api.foodashi.com/api/meal-plan/templates?goal=lose_weight" \
  -H "X-Api-Key: YOUR_API_KEY"
POST /api/shopping-list/from-recipes Indie+ 2 credits

Shopping List from Recipes

Generate a consolidated shopping list from multiple recipe IDs. Ingredients are merged, de-duplicated, and organized by USDA food groups (Produce, Protein, Dairy, Grains, Pantry, Beverages, Other).

cURL
curl -X POST "https://api.foodashi.com/api/shopping-list/from-recipes" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"recipe_ids": ["uuid-1", "uuid-2"], "unit_system": "metric"}'
POST /api/shopping-list/from-meal-plan Pro+ 2 credits

Shopping List from Meal Plan

Generate a shopping list directly from a meal plan (the shopping_list_compatible field from /api/meal-plan/generate). Automatically extracts all recipe IDs and applies per-meal servings overrides.

cURL
curl -X POST "https://api.foodashi.com/api/shopping-list/from-meal-plan" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"meal_plan": {"days": [{"meals": [{"recipe_id": "uuid", "servings": 2}]}]}}'

Each meal is bought for its servings, a number from 1 to 100, or for the recipe's own servings when you leave it out; repeated meals of one recipe add up, never capped. Any other servings value (0, negative, above 100, a string) is refused with a 400 invalid_parameter naming meal_plan.days[i].meals[j].servings.

POST /api/shopping-list/optimize Pro+ 150 credits

Optimize Shopping List

AI-powered shopping list optimization. Groups items by store aisle, suggests cheaper substitutions, estimates total cost, and provides storage tips.

cURL
curl -X POST "https://api.foodashi.com/api/shopping-list/optimize" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"recipe_ids": ["uuid-1", "uuid-2"], "unit_system": "metric", "preferences": {"budget": "normal", "diet": "none"}}'

A meal_plan body (instead of recipe_ids) follows the same servings rule as Shopping List from Meal Plan: 1 to 100 per meal, or omitted for the recipe's own servings.

POST /api/tips Indie+ 75 credits

Cooking & Prep Tips

AI-powered cooking and preparation tips for any ingredient or recipe name. Supports any language. Choose between cooking tips, prepping tips, or both. When a match is found in the database, tips are enriched with allergen, cuisine, and nutritional context for more specific advice.

Parameters

Parameter Type Required Description
name string Yes Ingredient or recipe name (any language, 1-200 chars)
type string Yes "ingredient" or "recipe"
tip_type string No "cooking", "prepping", or "both" (default: "both")
cURL
curl -X POST "https://api.foodashi.com/api/tips" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "chicken thigh", "type": "ingredient", "tip_type": "cooking"}'
Example Response
{
  "success": true,
  "data": {
    "name": "chicken thigh",
    "name_english": "Chicken Thigh",
    "type": "ingredient",
    "tip_type": "cooking",
    "tips": [
      {
        "category": "temperature",
        "title": "Optimal Internal Temperature",
        "tip": "Cook to 74°C (165°F) internal..."
      }
    ],
    "tip_count": 5,
    "db_enriched": true
  }
}
GET /stats

API Stats

Get aggregated statistics about the recipe database including counts by cuisine, dietary tags, allergens, equipment, and NutriMetric grades.

Example Response
{
  "total_recipes": 12847,
  "total_ingredients": 340000,
  "api_version": "3.0-pipeline",
  "status": "operational"
}

Response Schema

Example response from /api/recipes/details, as a paid plan receives it. nutrimetric and beverage_pairing are paid fields (Indie plan and above): see Paid Fields for what a Hobby key and the Test Kitchen receive.

{
  "id": "a1b2c3d4-e5f6-...",
  "title": "Caldo de Res",
  "title_english": "Mexican Beef Soup",
  "description": "A hearty Mexican beef soup...",
  "image_url": "https://...",
  "prep_time_minutes": 25,
  "cook_time_minutes": 90,
  "rest_time_minutes": 0,
  "active_time_minutes": 115,
  "total_time_minutes": 115,
  "requires_advance_preparation": false,
  "untimed_minutes": 17,
  "overlap_minutes": 0,
  "servings": 4,
  "cuisine": "Mexican",
  "cuisine_code": "MX",
  "meal_types": ["Dinner", "Main Course"],
  "dish_types": ["Stew"],
  "difficulty": "Medium",
  "cost_level": 2,
  "protein_source": ["Beef"],
  "tags": ["authentic", "comfort-food"],
  "cooking_methods": ["Braising", "Simmering"],
  "occasions": ["Weeknight Dinner"],
  "seasons": ["Winter", "Fall"],
  "equipment": ["Dutch Oven", "Knife"],
  "dietary_tags": ["Gluten-Free"],
  "allergens": ["Celery"],
  "allergen_declaration": {
    "framework": "EU Regulation 1169/2011 (14 allergens)",
    "declaration": {
      "contains": ["Celery"],
      "may_contain": [],
      "hidden_sources": [{ "allergen": "Celery", "hidden_in": ["beef stock"] }]
    },
    "note": "Derived from ingredient data to support your own labelling; not a legal declaration."
  },

  "nutrition": {
    "calories": 455,
    "protein_g": 35.2,
    "fat_g": 18.1,
    "saturated_fat_g": 5.2,
    "carbohydrate_g": 43.0,
    "fiber_g": 8.3,
    "sugars_total_g": 6.1,
    "sodium_mg": 850,
    "net_carbs_g": 34.7,
    "daily_value_percent": { "calories": 23, "protein_g": 70, "sodium_mg": 37, ... },
    "caloric_breakdown": { "percent_protein": 30, "percent_fat": 34, "percent_carbs": 36 },
    "per_100g": { "calories": 98, "protein_g": 7.6, "fat_g": 3.9, "carbohydrate_g": 9.3, "sodium_mg": 183 }
  },

  "nutrimetric": {
    "grade": "B",
    "score": 68,
    "label": "Good",
    "version": "nutrimetric-1.0"
  },

  "taste_profile": {
    "spicy": 3,
    "salty": 5,
    "sweet": 2,
    "umami": 7,
    "bitter": 1,
    "sour": 2,
    "scale": "1-10"
  },

  "storage": {
    "refrigerator_days": 3,
    "freezer_friendly": true,
    "reheating_instructions": "Reheat on stovetop..."
  },

  "beverage_pairing": { "wine": ["Tempranillo"], "beer": ["Negra Modelo"], "cocktails": ["Michelada"], "non_alcoholic": ["Agua de jamaica"], "spirits": [], "recommendations": ["A malty Negra Modelo matches the beef broth without overpowering the vegetables."] },

  "ingredients": [
    {
      "text": "450 g Beef chuck",
      "name": "Beef chuck",
      "quantity": 450,
      "unit": "g",
      "is_main": true,
      "preparation": "cubed",
      "optional": false,
      "gram_weight": 450,
      "purchase_gram_weight": 450
    },
    {
      "text": "900 g beef shank, bone-in",
      "name": "beef shank, bone-in",
      "quantity": 900,
      "unit": "g",
      "is_main": true,
      "preparation": null,
      "optional": false,
      "gram_weight": 630,
      "purchase_gram_weight": 900
    }
  ],

  "steps": [
    {
      "step": 1,
      "text": "Sear the beef...",
      "duration_minutes": 8,
      "temperature": null,
      "heat_level": "medium-high"
    },
    {
      "step": 2,
      "text": "Simmer until the beef is tender...",
      "duration_minutes": 90,
      "temperature": { "value": 95, "unit": "c" },
      "heat_level": null
    }
  ],

  "ai_generated": true,
  "provenance": { "text": "ai_generated", "ingredients": "ai_generated_db_resolved", "nutrition": "database_computed", "image": "ai_generated" }
}

Field types worth knowing.

  • allergen_declaration.declaration is an object (contains, may_contain with a reason for each, hidden_sources), never a sentence, or null. Render your own wording from it.
  • ingredients[].quantity is a number (fractions as decimals, such as 0.5), "" when the line gives no amount, or null for an unresolved line. It is never 0 for an unknown amount.
  • ingredients[].gram_weight is the edible grams the nutrition is computed on; purchase_gram_weight is the mass of the quantity as written, to buy (bone-in, shell-on, undrained), and equals gram_weight when nothing is removed before eating. Use it for shopping lists.
  • steps[].temperature is {value, unit} (unit is c or f; a range adds max_value) or null, and a freezer temperature keeps its sign (-18); a heat word such as medium is in heat_level, never turned into a number.
  • taste_profile scores each of the six tastes from 1 to 10.
  • Nutrient values can be null when a value is unknown, which is different from 0.

Understanding the time fields

Some dishes need an unattended wait, such as an overnight marinade, a proving dough, a week-long pickle. One number cannot honestly describe both how long you stand in the kitchen and when the dish will be ready, so we return both.

FieldMeaning
prep_time_minutesHands-on preparation.
cook_time_minutesAll cooking time, attended or not: a two-hour oven roast counts in full.
rest_time_minutesThe unattended wait: marinating, chilling, proving, fermenting, curing. You are not in the kitchen for this.
active_time_minutesPrep plus the cooking someone has to attend: never more than prep + cook, and less when part of the cooking runs on its own (an oven roast, a covered simmer), as it does for about a third of the catalogue. The figure to show on a card as “35 min”.
total_time_minutesprep + cook + rest. The wall clock, always. This is what max_time_minutes, min_time_minutes and sort=time_asc operate on, so a 30-minute query can never return a dish that needs an overnight soak.
requires_advance_preparationtrue when rest_time_minutes is 4 hours or more, i.e. the dish cannot be started and finished in one sitting. Use it for a “start the day before” badge.
untimed_minutesMinutes in the total that no step times: preparing the listed ingredients (washing, peeling, chopping what the ingredient list asks for) and a wait a step only implies. 0 when the steps time every minute.
overlap_minutesMinutes of step time that run alongside other steps (“meanwhile”, “while it bakes”), counted once in the total.

prep + cook + rest === total holds for every recipe, so does total === sum(steps[].duration_minutes) + untimed_minutes - overlap_minutes, active ≤ prep + cook, and active never includes rest. Publishers split this two ways and both work from these fields: AllRecipes and King Arthur show a separate “additional time” or “hands-on time” alongside the total, while NYT Cooking and BBC Good Food write “45 minutes, plus 8 hours’ marinating”.

// A 7-day pickle: honest total, usable headline
{
  "prep_time_minutes": 10,
  "cook_time_minutes": 18,
  "rest_time_minutes": 10080,
  "active_time_minutes": 28,
  "total_time_minutes": 10108,
  "requires_advance_preparation": true
}
// render as: "28 min active, plus 7 days pickling"

Available Cuisines (78)

East Asia

🇯🇵 Japanese🇨🇳 Chinese🇰🇷 Korean

Southeast Asia

🇹🇭 Thai🇻🇳 Vietnamese🇮🇩 Indonesian🇲🇾 Malaysian🇵🇭 Filipino🇸🇬 Singaporean🇲🇲 Burmese🇰🇭 Cambodian🇱🇦 Laotian

South & Central Asia

🇮🇳 Indian🇵🇰 Pakistani🇱🇰 Sri Lankan🇧🇩 Bangladeshi🇳🇵 Nepalese🏔️ Tibetan🇦🇫 Afghan

Middle East

🇹🇷 Turkish🇱🇧 Lebanese🇮🇷 Persian🇸🇾 Syrian🇮🇶 Iraqi🇮🇱 Israeli🇸🇦 Saudi Arabian🇾🇪 Yemeni

North Africa

🇲🇦 Moroccan🇹🇳 Tunisian🇪🇬 Egyptian

Europe

🇮🇹 Italian🇫🇷 French🇪🇸 Spanish🇬🇷 Greek🇵🇹 Portuguese🇩🇪 German🇬🇧 British🇮🇪 Irish🇵🇱 Polish🇷🇺 Russian🇺🇦 Ukrainian🇭🇺 Hungarian🇬🇪 Georgian🇦🇹 Austrian🇧🇪 Belgian🇨🇿 Czech

Nordic

🇩🇰 Danish🇸🇪 Swedish🇳🇴 Norwegian🇫🇮 Finnish🇮🇸 Icelandic

North America

🇺🇸 American🇲🇽 Mexican

South America

🇧🇷 Brazilian🇵🇪 Peruvian🇦🇷 Argentine🇨🇴 Colombian🇻🇪 Venezuelan🇨🇱 Chilean🇧🇴 Bolivian🇪🇨 Ecuadorian

Caribbean

🇨🇺 Cuban🇯🇲 Jamaican🇭🇹 Haitian🇩🇴 Dominican🇵🇷 Puerto Rican🇹🇹 Trinidadian🇧🇧 Barbadian

Pacific

🌺 Hawaiian🇦🇺 Australian

Sub-Saharan Africa

🇪🇹 Ethiopian🇳🇬 Nigerian🇿🇦 South African🇬🇭 Ghanaian🇸🇳 Senegalese🇹🇿 Tanzanian🇰🇪 Kenyan

Meal Types

Breakfast Brunch Lunch Dinner Starter Salad Soup Side Snack Dessert

Dietary Tags (21)

Lifestyle

Vegetarian Vegan Pescatarian

Low-Carb

Paleo Whole30 Keto Low-Carb

Nutritional

High-Protein Low-Fat Low-Sodium Low-Sugar

Allergen-Free

Gluten-Free Dairy-Free Egg-Free Soy-Free Nut-Free Shellfish-Free

Medical

Low-FODMAP Diabetic-Friendly Heart-Healthy

Regional

Mediterranean

Common Allergens (EU 14)

Track and filter recipes based on the 14 EU-regulated food allergens. Each recipe includes both confirmed allergens (detectedAllergens) and uncertain traces (mayContainAllergens).

🌾 Gluten
Common sources: wheat, rye, barley, oats, spelt, kamut
🦐 Crustaceans
Common sources: crab, lobster, shrimp, prawns
🥚 Eggs
Common sources: all egg products
🐟 Fish
Common sources: all fish species
🥜 Peanuts
Common sources: peanuts and peanut products
🫘 Soybeans
Common sources: soy and soy products
🥛 Dairy
Common sources: milk, cheese, butter, cream, lactose
🌰 Tree Nuts
Common sources: almonds, cashews, walnuts, pecans, pistachios
🥬 Celery
Common sources: celery and celeriac
🌭 Mustard
Common sources: mustard seeds and products
🫓 Sesame
Common sources: sesame seeds and oil
🍷 Sulphites
Common sources: sulphur dioxide and sulphites (>10mg/kg)
🫘 Lupin
Common sources: lupin seeds and flour
🐚 Molluscs
Common sources: squid, octopus, snails, clams, mussels

Kitchen Equipment (125)

Filter recipes by required kitchen equipment. Equipment is auto-detected from recipe instructions across all 80 world cuisines.

Pots & Pans

Pot Dutch Oven Skillet Sauté Pan Cast Iron Skillet Wok Griddle Crêpe Pan Paella Pan Roasting Pan Double Boiler Grill Grill Pan

Bakeware

Baking Sheet Baking Dish Cake Pan Loaf Pan Muffin Tin Pie Dish Springform Pan Bundt Pan Tart Pan Cooling Rack Pizza Stone Ramekin

Appliances

Oven Stovetop Microwave Blender Immersion Blender Food Processor Stand Mixer Hand Mixer Slow Cooker Pressure Cooker Air Fryer Rice Cooker Deep Fryer Toaster Oven Smoker Dehydrator Ice Cream Maker Sous Vide Waffle Iron Electric Kettle Bread Machine

Knives & Cutting

Knife Paring Knife Bread Knife Cleaver Cutting Board Kitchen Shears Mandoline Meat Mallet

Prep Tools

Mixing Bowl Whisk Spatula Wooden Spoon Rubber Spatula Tongs Ladle Slotted Spoon Rolling Pin Pastry Brush Piping Bag Bench Scraper Sieve Strainer Grater Peeler Zester Garlic Press Can Opener Mortar and Pestle Citrus Juicer Potato Masher Salad Spinner Meat Grinder Potato Ricer Cherry Pitter Apple Corer

Measuring

Measuring Cups Measuring Spoons Kitchen Scale Thermometer Timer

World Cuisine Specialty

East & Southeast Asian Bamboo Steamer Steamer Sushi Mat Takoyaki Pan Clay Pot Korean Stone Bowl Dumpling Press Spider Strainer Wok Ring
South Asian Tandoor Tawa Idli Maker Pressure Pan
Middle Eastern & North African Tagine Couscous Pot Pita Oven
Latin American Tortilla Press Molcajete Comal Empanada Press Churrera
European Pasta Machine Pizza Peel Fondue Pot Raclette Grill Crêpe Maker Spätzle Maker Pierogi Press
African Injera Griddle
General Specialty Skewers Mold Blowtorch Smoking Gun Fermentation Crock Spice Grinder Food Mill Chinois Fish Scaler Canning Jars

Changelog

What's new in the Foodashi API. We ship data-quality and capability improvements continuously.

API v1 Stable — current

Call any endpoint as /api/v1/… (unversioned /api/… paths keep working). Every response returns an X-API-Version header so you always know which contract you received. Browser JavaScript on an allowed origin can read it too, with the rate limit, monthly allowance, overage, request cost, warning and Retry-After headers: the API lists them in Access-Control-Expose-Headers.

Our compatibility promise: within v1 we only add — we never remove or rename a field, or change the shape of a response. Anything breaking would ship as /api/v2/, and v1 would keep running. The releases below are improvements inside v1; none of them require you to change your code, with two exceptions. In v5.6 a locked paid field on a Hobby key became a {"locked": true} object instead of null or {}. In v5.8 a nutrient value the data does not state became null instead of 0 on the ingredient, barcode and ad hoc analysis endpoints, and requests that used to be answered wrongly (an unknown browse parameter, a non-mass unit on ad hoc analysis, meal servings outside 1 to 100) are refused with a 400; a check or read the API could not complete is a retryable 503 instead of a guess.

2026 9 releases
v5.8 Latest 13 October 2026 #
  • Added purchase_gram_weight on every ingredient line: the mass to buy (bone-in, shell-on, undrained), beside gram_weight, the edible grams the nutrition is computed on. Scale lines add scaled_purchase_gram_weight. Additive, no version change.
  • Fixed The OpenAPI document and the examples now describe the recipe object exactly as served: allergen_declaration.declaration is an object, ingredient quantities are numbers, steps[].temperature is {value, unit} or null with heat_level beside it, taste scores run 1 to 10, and unknown values are typed as null (OpenAPI 3.1). Clients generated from the old document may need regenerating.
  • Fixed When the data behind an answer cannot be read, the API now answers 503 with code service_unavailable and "retryable": true instead of a partial or empty success: recipe lists, details, bulk lookup, similar, a single random recipe and by-ingredients, the three shopping list endpoints, ingredient search, details and batch, ad hoc analysis and nutrition calculate. Retry the request. Random with count above 1 leaves out a recipe that cannot be read and says so with "partial": true and failed_ids.
  • Fixed When your account’s quota or extra-usage check cannot answer, every metered endpoint now answers 503 with code service_unavailable and "retryable": true and serves nothing. Such a call used to be served without being counted, or refused as over quota. Retry the request. Errors
  • Fixed 429 overage_depleted now means your prepaid extra usage really cannot pay for the call. A balance check that does not answer is a 503, and it no longer starts an automatic top-up.
  • Fixed Too many API key lookups from one client address (120 per minute) now answer 429 rate_limited with "limit": 120 and a Retry-After in seconds. They used to answer quota_exceeded with a Retry-After at the end of the month. Rate limits
  • Fixed By ingredients: exclude=egg now leaves out every recipe that holds egg; it used to miss most of them. A term that cannot be read is a 503.
  • Fixed Analyze text, analyze URL and meal logging answer 503 service_unavailable when a nutrient read fails after the AI step, instead of totals that leave the food out or count it as zero.
  • Improved Food recognition: when the recipe lookup fails after a dish is identified, the answer keeps the identification and says "partial": true with errors, so an empty matched_recipes on its own always means no recipe matched. Dish names written with vowel signs, such as Devanagari, Thai, Tamil or Bengali, now find their recipes.
  • Improved Nutrition calculate reads each line’s optional preparation: butter with "unsalted, softened" is costed as unsalted butter.
  • Fixed A nutrient value the data does not state is now null, never 0: ingredient details and batch (nutrition_per_100g), barcode (nutrition, each gap named in nutrition_gaps) and ad hoc analysis (each line and every total it enters). A measured 0 stays 0. Shape change: if your code adds these values up, treat null as unknown.
  • Fixed Every /api/recipes/by-* endpoint now reads exclude_allergens, exclude_alg and allergen alike, and refuses a parameter name it does not read with 400 unknown_parameter (listing accepted_parameters). A misspelt or alias allergen filter used to be ignored, so the page kept the recipes it should have excluded. /api/recipes/by-ingredients now applies the shared browse filters too. Browse conventions
  • Fixed Ad hoc analysis weighs mass units only (g, kg, mg, lb, oz and their spellings). A volume or piece unit, or an amount that is not a number from 0, is refused with 400 invalid_parameter; any other unit used to be read as grams, so 2 cups weighed 2 g and 500 mg weighed 500 g.
  • Fixed Shopping lists from a meal plan buy for every meal: a meal without servings counts the recipe's own servings, and totals are never capped. Meal servings must be 1 to 100, or the request is refused with 400 invalid_parameter.
  • Fixed Daily needs refuses inputs outside what its equation describes with a 400 instead of a negative or empty target, and nutrition calculate answers 422 when no matched food has nutrient data instead of a 200 with empty figures.
  • Improved Sustainability: milk and white chocolate have their own food class, milk or white chocolate, counted as animal-based (milk chocolate used the factor of plain milk, and white chocolate counted as plant-based). Dark chocolate that states its cocoa content now uses the chocolate factor instead of the cocoa powder one.
  • Improved Browser code on an allowed origin can send Authorization: Bearer and read X-API-Version, the X-RateLimit-* and X-Monthly-* headers, X-Overage-Active, X-Request-Cost, X-Foodashi-Warning, X-Edge-Cache and Retry-After.
  • Fixed A step temperature below zero, such as a freezer at -18°C, keeps its minus sign in steps[].temperature.
v5.7 7 October 2026 #
  • Improved Dishes cooked with wine, beer or spirits now count only the alcohol that survives the cooking, worked out from how long the recipe cooks it after the drink goes in (USDA retention factors). A long wine braise no longer carries all of the wine’s alcohol energy.
  • Improved An ingredient listed without an amount, such as sugar for dusting, flour for the work surface or oil for greasing and drizzling, now adds a typical amount to the recipe’s nutrition instead of nothing.
  • Improved An ingredient described as pitted or unsalted now uses nutrition for exactly that form, such as stoneless prunes or unsalted butter.
  • Improved Allergen warnings cover more bought ingredients: miso warns for gluten, generic stock warns for celery, and blends such as asafoetida, dashi powder and fermented bean pastes carry the warnings their common commercial forms need. A free-from label is withheld when an ingredient’s allergens cannot be confirmed.
  • Improved Nutrition claims and diet tags such as Low-Fat, Low-Sodium and High-Protein are awarded only when a recipe sits comfortably inside the limit, allowing for the natural variation of a calculated recipe, not when it only just scrapes past it.
  • Improved equipment now lists every tool the steps use, such as a whisk, a wire rack or a slotted spoon, and drops listed tools nothing uses. Tool names are written one way everywhere, so the equipment filter finds every recipe that needs a tool.
  • Improved Storage advice always sends cooked moist dishes such as soups, stews, curries and bean dishes to the fridge.
  • Improved beverage_pairing always carries the same six lists (wine, beer, cocktails, non_alcoholic, spirits, recommendations), empty when there is nothing of that kind, or is null when a recipe has no pairing.
  • Added untimed_minutes and overlap_minutes on every recipe: the total now adds up from the steps, total_time_minutes = sum(steps[].duration_minutes) + untimed_minutes - overlap_minutes, exactly, so you can show or check where every minute goes.
  • Improved A step whose text states a temperature (“until it reaches 70°C”, “heat the oil to 180°C (350°F)”) now serves it in temperature as {value, unit} instead of null.
  • Improved Prep, cook and rest times follow what each step does: a step that opens with a condition (“once cool”, “just before serving”) and then works is counted as work, not waiting. Rich desserts that served a whole pot to four people are portioned realistically.
v5.6 30 September 2026 #
  • Added POST /api/v1/recipes/{id}/reports: let your users report a recipe that looks wrong, such as a missing allergen, a wrong diet tag or a wrong step. Free on every plan: 0 credits, and it works even when your key is over its monthly quota. Allergen and diet tag reports reach the Foodashi team straight away.
  • Improved A paid field your plan does not include now says which plan unlocks it. Shape change for Hobby keys: nutrimetric and beverage_pairing are now {"locked": true, "available_on": "indie", "message": "..."} instead of null or {}. If your Hobby app checked for null, check locked instead. Paid plans are unchanged. Paid Fields
  • Improved The Test Kitchen now shows every field on every plan, with a field_plans object naming the plan that includes each paid field, so you can see exactly what each plan returns before choosing one.
  • Improved Sustainability now returns the recipe's climate footprint in kg CO2 equivalent per serving and per recipe, with the plant-based share, the top contributing ingredients and the estimate's coverage. Shape change: the endpoint no longer repeats the NutriMetric grade and the diet tags, which are on the recipe itself.
  • Added POST /api/analyze/text and /api/analyze/url now return the climate footprint of the recipe you send, in the same sustainability shape. No extra credits.
  • Improved Every recipe sub-resource (nutrition, taste, allergens, sustainability, beverages, medical, scale) now includes title_english beside the native title, and answers errors with a code (invalid_id, not_found) like the full recipe.
  • Added Attribution: the Hobby plan requires a visible “Powered by Foodashi” credit linking to foodashi.com wherever Foodashi data is shown, with a copy-paste snippet. Paid plans need no Foodashi credit.
v5.5 September 2026 #
  • Added Allergen recognition in many more languages: native ingredient names from our 80 cuisines are now matched to the 14 major allergens defined by EU law.
  • Improved Engine update 2026.09: every nutrition value now comes from one unified calculation, identical when a recipe is created and whenever it is updated, so the numbers match across every endpoint.
  • Improved More accurate ingredient weights, based on USDA reference portions for cups, spoons and whole pieces of each named food.
  • Improved Serving sizes follow the dish: breads, desserts, pastries, snacks and batch recipes are now portioned realistically.
  • Improved Diet claims such as Low-Fat, Low-Sodium and Low-Carb are shown only when the whole recipe supports them.
  • Improved Cooking times are more precise: prep, cook and total time are measured from the method, and overnight soaking or marinating is counted once.
  • Improved Fried, soaked and cured dishes: absorbed frying oil and salt removed by soaking are now modelled more accurately.
  • Improved Stability and consistency improvements across the recipe, nutrition and search endpoints. Existing recipes are being brought up to the new engine progressively.
v5.4 July 2026 #
  • Added New endpoint POST /api/nutrition/calculate — send a structured ingredient list and get full per-serving, per-100g and total nutrition plus a NutriMetric grade. Deterministic and AI-free, so it is fast, repeatable and costs 5 calls. Indie and above.
  • Improved Broader EU-14 allergen coverage for international cooking — ingredients such as dashi, gochujang, za’atar, prahok, kecap manis and belacan are now recognised by name, along with hidden-source terms like casein, semolina and gingelly.
  • Improved Allergen declarations, dietary tags and the EU compliance block are now reconciled end-to-end, so every recipe tells one consistent story.
  • Improved Sharper crustacean and mollusc separation, matching the two distinct Annex II categories.
  • Improved Higher nutrition precision: energy values cross-checked against source data, and per-serving figures verified across the catalogue.
  • Improved NutriMetric grades now move in lockstep with the nutrition they score.
v5.3 June 2026 #
  • Improved More accurate nutrition: gram-weighted nutrient coverage and consistent per-serving math across the catalog.
  • Added Two-axis taxonomy on every recipe: dish_types[] (what a dish is) and meal_types[] (when it's eaten).
  • Improved Higher recipe authenticity — canonical-dish fidelity checks at generation and native dish names.
  • Improved Stronger EU-14 allergen and dietary-tag accuracy, with confirmed vs. may-contain flags.
v5.2 March 2026 #
  • Added AI Vision endpoints: Recognize Dish and Recognize Ingredients (Pro).
  • Added Beverage Pairing AI Sommelier endpoint.
  • Improved Variable endpoint costs (AI endpoints cost 3–25 credits) and clearer error messages with debug hints.
v5.1 February 2026 #
  • Added Meal Planning (Generate, Customize, Templates) and Shopping List generation.
  • Added NutriMetric scoring system (A–F nutrition grades).
  • Improved Overage billing for Indie/Pro tiers.
v5.0 January 2026 #
  • Added Vector-powered semantic search (Smart Search) and 70+ endpoints across 11 categories.
  • Improved Complete API rewrite on Cloudflare Workers (5× faster).
  • Added Tier-based access control (Hobby / Indie / Pro).