Foodashi API
The complete recipe API for modern food applications. Search by flavor, nutrient, or ingredient with vector-powered semantic search.
# 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.
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.
{
"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 Hobby54 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
+ AIAll 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
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:
<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": "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.
/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 -X GET "https://api.foodashi.com/api/recipes?cuisine=Mexican&exclude_alg=Peanuts&limit=2" \ -H "X-Api-Key: YOUR_API_KEY"
Example Response
{
"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 }
}
/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 -X GET "https://api.foodashi.com/api/recipes/details?id=b1a2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "X-Api-Key: YOUR_API_KEY"
Example Response
{
"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.
/api/random
Hobby+
1 credit
Random Recipe
Returns a random recipe, great for "Surprise Me" features. Every filter is optional and they combine.
| Parameter | Type | Description |
|---|---|---|
| tags | string | CSV; each token must match a meal type (dinner), dish type (soup) or recipe tag |
| cuisine | string | Cuisine name, case-insensitive (e.g. Italian) |
| diet | string | Dietary tag, case-insensitive; CSV means all listed; unknown value returns 400 with valid_diets |
| meal_type | string | Meal type (e.g. Dinner) |
| dish_type | string | Dish type (e.g. Soup) |
| exclude_allergens | string | CSV of EU-14 allergens to exclude, case-insensitive (aliases allergen, exclude_alg); an unknown name returns 400 invalid_allergen |
| count | integer | 1-10, default 1 |
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)
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number, 1-based (default: 1). |
| limit | integer | Results per page (default: 20, max: 100). For ingredient endpoints max is 50. |
| offset | integer | Row 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:
| Parameter | Value | Notes |
|---|---|---|
| random | true | Most common form. |
| sort | random | Alternative spelling (consistent with the sort param on /api/recipes/filter). |
| shuffle | true | Alternative 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.
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 whoseseasons[]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:
chickenmatches "chicken breast", "ground chicken", etc. Use longer phrases for specificity. - • Typo-intolerant:
red ononreturns 0 — call/api/ingredients/autocompletefirst 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).
| Parameter | Type | Description |
|---|---|---|
| meal_type / meal_types | CSV | Include recipes whose meal_types[] match any listed value. Example: meal_types=Dinner,Lunch. |
| dish_type / dish_types | CSV | Include recipes whose dish_types[] match any listed value. Example: dish_types=Pasta,Pizza. |
| exclude_meal_types | CSV | Drop recipes whose meal_types[] match any listed value. Example: exclude_meal_types=Dessert,Appetizer,Side. |
| exclude_dish_types | CSV | Drop recipes whose dish_types[] match any listed value. Example: exclude_dish_types=Salad,Cake. |
| exclude_diets | CSV | Drop recipes tagged with any listed diet. Example: exclude_diets=Vegan. |
| min_time_minutes / max_time_minutes | integer | Total-time bounds (prep + cook + rest), in minutes. Combine the two for a range. See the time fields for how total, active and rest relate. |
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.
/api/recipes/by-cuisine
Hobby+
1 credit
Browse by Cuisine
Browse recipes filtered by cuisine type. Returns lightweight recipe cards with pagination.
| Parameter | Type | Description |
|---|---|---|
| cuisine Required | stringRequired | Cuisine name (e.g., "Italian", "Mexican", "Japanese") |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-cuisine?cuisine=Italian&limit=10" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
/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.
| Parameter | Type | Description |
|---|---|---|
| regionRequired | string | One 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 |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
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 } }
/api/recipes/by-continent
Hobby+
1 credit
Browse by Continent
Broadest geographic filter. Useful for top-level navigation like “Asian cuisine” or “European cuisine”.
| Parameter | Type | Description |
|---|---|---|
| continentRequired | string | One of: Asia, Europe, Africa, Americas, Oceania, Global |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-continent?continent=Asia&limit=30" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| countryRequired | string | ISO-3166-1 alpha-2 country code (case-insensitive). Example: JP, IT, BR, MX, IN, MY. |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
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.
/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.
?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
| Parameter | Type | Description |
|---|---|---|
| cuisine | string | Exact cuisine name. See 80 valid cuisines. Example: Italian, Thai, Sri Lankan. |
| region | string | Sub-continental region. See 14 valid regions. Example: Southeast Asia, Southern Europe. |
| continent | string | Africa, Americas, Asia, Europe, or Oceania. |
| country | string | ISO-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
| Parameter | Type | Description |
|---|---|---|
| meal_type / meal_types | string / CSV | WHEN 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_types | string / CSV | WHAT 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_types | CSV | Comma-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_types | CSV | Comma-separated dish types — drop recipes whose dish_types[] include any listed value. Case-insensitive; unknown values ignored. Example: exclude_dish_types=Salad,Cake. |
| difficulty | string | Easy, Medium, or Hard. |
Filters — Diet, Tags & Allergens
| Parameter | Type | Description |
|---|---|---|
| diet | string | One dietary tag the recipe must satisfy. See 11 dietary tags. Example: Vegan, Gluten-Free. |
| exclude_diets | CSV | Comma-separated dietary tags — drop recipes tagged with any listed diet. Case-insensitive; unknown values ignored. Example: exclude_diets=Vegan. |
| tag | string | Single free-form tag the recipe must have. Example: weeknight-dinner, comfort-food. |
| include_tags | CSV | Comma-separated tags — recipe must contain all of them. Example: comfort-food,weeknight-dinner. |
| exclude_tags | CSV | Comma-separated tags — recipe must contain none of them. |
| exclude_allergens | CSV | EU-14 allergens to filter out. See 14 valid allergens. Example: Eggs,Dairy,Nuts. |
Filters — Time, Servings & Cost
| Parameter | Type | Description |
|---|---|---|
| max_time_minutes | integer | Max 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_minutes | integer | Min total time. Combine with max_time_minutes for a range. |
| min_servings | integer | Minimum servings (useful for batch cooking). |
| max_servings | integer | Maximum servings. |
| servings | integer | Exact servings. |
| max_prep_minutes | integer | Max prep time, in minutes. |
| cost_level_max | integer | 1 (budget) to 4 (luxury). |
Filters — Technique & Context
| Parameter | Type | Description |
|---|---|---|
| cooking_method | string | Single technique. See 59 valid methods. Example: baked, grilled, steamed, stir-fried. |
| equipment | string | Single piece of equipment the recipe uses. Example: wok, cast iron skillet, oven, slow cooker. |
| occasion | string | See 7 valid occasions. Example: Weeknight, Holiday, Barbecue. |
| season | string | Spring, 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
| Parameter | Type | Description |
|---|---|---|
| min_calories | number | Min kcal per serving. |
| max_calories | number | Max kcal per serving. |
| min_protein_g | number | Min grams of protein per serving. |
| max_protein_g | number | Max grams of protein per serving. |
| min_fat_g | number | Min grams of fat per serving. |
| max_fat_g | number | Max grams of fat per serving. |
| min_carbs_g | number | Min grams of carbohydrate per serving. |
| max_carbs_g | number | Max grams of carbohydrate per serving. |
| min_fiber_g | number | Min grams of fiber per serving. |
| max_sugar_g | number | Max grams of sugars per serving. |
| max_sodium_mg | number | Max milligrams of sodium per serving. |
| nutrimetric_min_grade | string | Foodashi NutriMetric grade gate. A, B, C, D, E or F. Value passes if recipe’s grade is ≥ requested grade (A is best). |
| has_image | boolean | true = only recipes with images; false = only without. |
Sort & Pagination
| Parameter | Type | Description |
|---|---|---|
| sort | string | recent (default, newest first; alias newest), time_asc (fastest first), time_desc, nutrimetric (best score first), or random. |
| random | boolean | Shuffle results — see browse conventions. |
| limit | integer | Results per page (default: 20, max: 100). |
| page | integer | Page number (default: 1). |
| offset | integer | Row 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 -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 -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 -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
{
"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_tagssparingly; it performs a GIN array-contains scan. Max 10 tags. - •
limit=100is the ceiling. For >100 results, paginate withpage=2, etc. - •
filterin the response echoes the parameters the server applied; a misspelt parameter name returns400unknown_parameterinstead 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.
SoupStewCurryPorridgeSandwichWrapBurgerHot DogSpring RollPastaNoodle DishStuffed PastaRice DishFried RiceSushiGrain DishSaladSlawCevicheTartareStir-FryGrilled DishRoastBraised DishSteamed DishBarbecueSkewerFried DishFritterCutletCroquetteCasseroleGratinQuicheSavory PieSouffléDumplingEmpanadaHand PiePizzaCalzoneStuffed FlatbreadBreadFlatbreadCornbreadPancakeCrepeWaffleOmeletScrambled EggsEgg DishBean DishLentil DishTofu DishVegetable DishStuffed VegetableFondueCheese PlateSausageCharcuterieCured FishJerkySteakRoast MeatRibsMeatballGround Meat DishFish FilletWhole FishShellfishCakeCheesecakeCookieSweet PiePastryPuddingCustardFrozenConfectionJellyAssembledCrumbleSauceDressingMarinadeDipSpreadSpice PasteYogurt DishPickleJamCompoteSmoothieMilkshakeJuiceCocktailMocktailTeaCoffeeHot ChocolateFermented BeverageCrackerGranolaEnergy BarPopcornMixed PlateBowlmeal_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).
BreakfastBrunchLunchDinnerLate NightAppetizerSideMain CourseDessertSnackTea TimeAperitifDrinkStreet FoodCondimentComponentcuisine — 80 valid values
Pass to cuisine=. Case-sensitive exact match.
AustrianBelgianBritishCzechDanishFinnishFrenchGeorgianGermanGreekHungarianIcelandicIrishItalianNorwegianPolishPortugueseRussianSpanishSwedishUkrainianChineseJapaneseKoreanTibetanBurmeseCambodianFilipinoIndonesianLaotianMalaysianSingaporeanThaiVietnameseAfghanBangladeshiIndianNepalesePakistaniSri LankanAlgerianArmenianEgyptianIraqiIsraeliLebaneseMoroccanPersianSaudi ArabianSyrianTunisianTurkishYemeniBenineseEthiopianGhanaianKenyanNigerianSenegaleseSouth AfricanTanzanianAmericanHawaiianMexicanArgentineBarbadianBolivianBrazilianChileanColombianCubanDominicanEcuadorianHaitianJamaicanPeruvianPuerto RicanTrinidadianVenezuelanAustralianregion — 14 valid values
Pass to region=. Sub-continental grouping.
CaribbeanEast AsiaEastern EuropeLatin AmericaMiddle EastNorth AfricaNorth AmericaNorthern EuropeOceaniaSouth AsiaSoutheast AsiaSouthern EuropeSub-Saharan AfricaWestern Europecontinent — 5 valid values
AfricaAmericasAsiaEuropeOceaniadiet: 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-HealthyMediterraneanexclude_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 NutsCeleryMustardSesameSulfitesLupinMolluscscooking_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-bathwhippedwhiskingoccasion — 7 valid values
Pass to occasion=. Title-case.
EverydayWeeknightFamily MealMeal PrepBarbecuePartyHolidayseason — 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-Roundequipment — 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 pinmandolinecountry — 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/api/recipes/by-diet
Hobby+
1 credit
Browse by Diet
Filter recipes by dietary tag. Searches within the recipe's dietary_tags array.
| Parameter | Type | Description |
|---|---|---|
| diet Required | stringRequired | Dietary tag (e.g., "Vegan", "Keto", "Gluten-Free") |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-diet?diet=Vegan&limit=10" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| type Required | stringRequired | Meal type (e.g., "Breakfast", "Dinner", "Dessert") |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-meal-type?type=Breakfast" \ -H "X-Api-Key: YOUR_API_KEY"
/api/recipes/by-time
Hobby+
1 credit
Browse by Time
Find quick recipes by specifying a maximum total cook time in minutes.
| Parameter | Type | Description |
|---|---|---|
| maxMinutes | integerRequired | Maximum total time in minutes (e.g., 30) |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-time?maxMinutes=30" \ -H "X-Api-Key: YOUR_API_KEY"
/api/recipes/by-difficulty
Hobby+
1 credit
Browse by Difficulty
Filter recipes by difficulty level: Easy, Medium, or Hard.
| Parameter | Type | Description |
|---|---|---|
| difficulty Required | stringRequired | Difficulty level: "Easy", "Medium", or "Hard" |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-difficulty?difficulty=Easy" \ -H "X-Api-Key: YOUR_API_KEY"
/api/recipes/count
Hobby+
1 credit
Recipe Count
Get the total number of published recipes. Supports optional filters to count subsets.
| Parameter | Type | Description |
|---|---|---|
| cuisine | string | Filter by cuisine |
| diet | string | Filter by dietary tag |
| difficulty | string | Filter by difficulty |
curl -X GET "https://api.foodashi.com/api/recipes/count?cuisine=Italian" \ -H "X-Api-Key: YOUR_API_KEY"
/api/recipes/cuisines
Hobby+
1 credit
List Cuisines
Get all cuisines that have published recipes, with recipe counts for each.
curl -X GET "https://api.foodashi.com/api/recipes/cuisines" \ -H "X-Api-Key: YOUR_API_KEY"
/api/recipes/diets
Hobby+
1 credit
List Dietary Tags
Get all dietary tags with recipe counts. Useful for dietary filter UIs.
curl -X GET "https://api.foodashi.com/api/recipes/diets" \ -H "X-Api-Key: YOUR_API_KEY"
/api/autocomplete
Indie+
1 credit
Autocomplete
Extremely fast search for UI search bars. Returns lightweight titles matching the query.
| Parameter | Type | Description |
|---|---|---|
| query | stringRequired | Search text (min 2 chars) |
| limit | integer | Max results (default 5, max 10) |
curl -X GET "https://api.foodashi.com/api/autocomplete?query=chick" \ -H "X-Api-Key: YOUR_API_KEY"
/api/bulk-lookup
Indie+
2 credits
Bulk Lookup
Fetch details for multiple recipes in a single API call. Essential for "Favorites" lists.
| Parameter | Type | Description |
|---|---|---|
| ids | stringRequired | Comma-separated recipe UUIDs (max 50). Ids that are not UUIDs come back in invalid_ids. |
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"
/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.
| Parameter | Type | Description |
|---|---|---|
| id | uuidRequired | Source recipe UUID |
| limit | integer | Max results (default 5, max 20) |
curl -X GET "https://api.foodashi.com/api/similar?id=3f8a1c2e-9b4d-4e6f-8a2b-1c3d5e7f9a0b" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| method | stringRequired | Cooking method (e.g., "grilling", "baking", "stir-frying") |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-cooking-method?method=grilling" \ -H "X-Api-Key: YOUR_API_KEY"
/api/recipes/by-equipment
Indie+
1 credit
Browse by Equipment
Find recipes that use specific kitchen equipment like air fryer, slow cooker, or wok.
| Parameter | Type | Description |
|---|---|---|
| equipment | stringRequired | Equipment name (e.g., "oven", "air fryer", "slow cooker") |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-equipment?equipment=air+fryer" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| occasion | stringRequired | Occasion name (e.g., "Christmas", "BBQ", "Date Night") |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-occasion?occasion=Christmas" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| season | stringRequired | One of: Spring, Summer, Fall (or alias Autumn), Winter, Year-Round. Case-insensitive. |
| random | boolean | Shuffle results — see browse conventions. Aliases: sort=random, shuffle=true. |
| page | integer | Page number (default: 1). |
| limit | integer | Results per page (default: 20, max: 100). |
curl -X GET "https://api.foodashi.com/api/recipes/by-season?season=Spring&limit=20" \ -H "X-Api-Key: YOUR_API_KEY"
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.
/api/search
Indie+
2 credits
Smart Search
Vector-powered semantic search. Find recipes by describing what you want in natural language — e.g. "spicy dinner under 500 cals", "comfort food for winter", "easy weeknight pasta".
Always returns results
If the embedding service is temporarily unavailable (rate limit, quota, network), this endpoint automatically falls back to a text match on title / title_english / description so your app keeps working. When this happens the response includes meta.mode = "text_fallback" with a note explaining the degradation. Vector-mode and text-fallback responses share the same shape.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| q Required | stringRequired | Natural language search query (e.g. "spicy dinner under 500 cals") |
| limit | integer | Max results, 1-50 (default 20). |
| cuisine | string | Cuisine name, case-insensitive |
| diet | string | Dietary tag, case-insensitive; CSV means all listed; unknown value returns 400 with valid_diets |
| meal_type | string | Meal type (e.g. Dinner) |
| dish_type | string | Dish type (e.g. Soup) |
| exclude_allergens | string | CSV of EU-14 allergens to exclude, case-insensitive (aliases allergen, exclude_alg); an unknown name returns 400 invalid_allergen |
curl -X GET "https://api.foodashi.com/api/search?q=comfort+food+for+winter&limit=5" \ -H "X-Api-Key: YOUR_API_KEY"
Response
Both modes return the same card. similarity is null on text_fallback.
{
"success": true,
"query": "comfort food for winter",
"count": 5,
"filters_applied": false,
"data": [
{
"id": "3f8a1c2e-9b4d-4e6f-8a2b-1c3d5e7f9a0b",
"title": "Pot-au-feu",
"title_english": "Beef and Vegetable Stew",
"description": "...",
"image_url": "https://...",
"cuisine": "French",
"cuisine_code": "FR",
"difficulty": "Medium",
"total_time_minutes": 210,
"servings": 6,
"dietary_tags": ["Dairy-Free"],
"allergens": ["Celery"],
"meal_type": "Dinner",
"meal_types": ["Dinner", "Main Course"],
"dish_types": ["Stew"],
"published_at": "2026-05-10T09:00:00Z",
"similarity": 0.8123
}
],
"meta": { "mode": "semantic", "semantic_ranking": true, "tier": "indie" }
}
meta.mode is "semantic" or "text_fallback".
/api/recipes/by-nutrients
Pro+
3 credits
Browse by Nutrients
Filter recipes by nutrient ranges. Find high-protein, low-calorie, or custom macro recipes.
| Parameter | Type | Description |
|---|---|---|
| minCalories | number | Minimum calories per serving |
| maxCalories | number | Maximum calories per serving |
| minProtein | number | Minimum protein (g) per serving |
| maxProtein | number | Maximum protein (g) per serving |
| minCarbs | number | Minimum carbs (g) per serving |
| maxCarbs | number | Maximum carbs (g) per serving |
| minFat | number | Minimum fat (g) per serving |
| maxFat | number | Maximum fat (g) per serving |
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/recipes/by-nutrients?minProtein=25&maxCalories=500" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| include | stringRequired* | 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. |
| exclude | string | Comma-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. |
| random | boolean | Shuffle results — see browse conventions. |
| page | integer | Page number (default: 1). |
| limit | integer | Results 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 ONIONall match identically. - • Whitespace-normalized:
red onion(extra spaces) matches the same asred onion. - • Plural-tolerant:
onion=onions,tomato=tomatoes,cherry=cherries. No need to guess what form the catalogue uses. - • Substring match:
chickenmatches "chicken breast", "ground chicken", "chicken thigh", etc. To be more specific, use a longer phrase likechicken breast. - • Typo-intolerant:
red ononreturns 0. For fuzzy/typo matching, hit/api/ingredients/autocompletefirst 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 onionin their original ingredient text. You get the result you expect without having to know about internal canonical IDs.
curl -X GET "https://api.foodashi.com/api/recipes/by-ingredients?include=red%20onion&limit=10" \ -H "X-Api-Key: YOUR_API_KEY"
curl -X GET "https://api.foodashi.com/api/recipes/by-ingredients?include=chicken,rice&limit=20" \ -H "X-Api-Key: YOUR_API_KEY"
curl -X GET "https://api.foodashi.com/api/recipes/by-ingredients?include=chicken,rice&exclude=nuts,dairy" \ -H "X-Api-Key: YOUR_API_KEY"
{
"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
| Status | Body | When |
|---|---|---|
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. |
/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.
| Parameter | Type | Description |
|---|---|---|
| :id | uuidRequired | Recipe UUID |
curl -X GET "https://api.foodashi.com/api/recipes/{id}/nutrition" \ -H "X-Api-Key: YOUR_API_KEY"
/api/recipes/:id/allergens
Indie+
1 credit
Recipe Allergens
Allergen declaration covering all 14 EU-regulated allergens, hidden allergen sources, and cross-contamination warnings.
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.
/api/recipes/:id/beverages
Indie+
1 credit
Beverage Pairing
AI-generated beverage pairing suggestions including wine, beer, cocktails, and non-alcoholic options.
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"}.
/api/recipes/:id/scale
Indie+
1 credit
Scale Servings
Recalculate all ingredient quantities for a different number of servings.
| Parameter | Type | Description |
|---|---|---|
| :id | uuidRequired | Recipe UUID |
| servings | integerRequired | Target number of servings (1-100) |
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.
/api/recipes/:id/taste
Pro+
3 credits
Taste Profile
6-axis taste profile rated 1-10: sweetness, saltiness, sourness, bitterness, savoriness, and spiciness.
curl -X GET "https://api.foodashi.com/api/recipes/{id}/taste" \ -H "X-Api-Key: YOUR_API_KEY"
/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 inuncovered_ingredientsand never guessed.food_class: the food class each top contributor was costed as, a readable label such asbeef,cheese,chocolateormilk or white chocolate. Milk and white chocolate count as animal-based inplant_based_share.- Source: climate factors from ADEME AGRIBALYSE v3.2 (see Data Sources).
curl -X GET "https://api.foodashi.com/api/recipes/{id}/sustainability" \ -H "X-Api-Key: YOUR_API_KEY"
{
"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 …"
}
}
/api/recipes/:id/medical
Pro+
3 credits
Medical Cautions
Medical caution flags for conditions like diabetes, hypertension, gout, and kidney disease.
curl -X GET "https://api.foodashi.com/api/recipes/{id}/medical" \ -H "X-Api-Key: YOUR_API_KEY"
/api/recipes/compare
Pro+
4 credits
Compare Recipes
Side-by-side nutritional comparison of 2-5 recipes.
| Parameter | Type | Description |
|---|---|---|
| ids | stringRequired | Comma-separated recipe UUIDs (2-5 IDs) |
curl -X GET "https://api.foodashi.com/api/recipes/compare?ids=uuid1,uuid2" \ -H "X-Api-Key: YOUR_API_KEY"
/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)
| Field | Type | Description |
|---|---|---|
| :id Required | uuid | The recipe UUID, in the path. It must be a published recipe, or the answer is 404 recipe_not_found. |
| reasons Required | string[] | One or more of the reasons below (multi-select). A repeated reason counts once. |
| comment | string | Optional, at most 500 characters. Links are removed. Required when reasons includes other (a comment that is only a link counts as empty). |
| end_user_ref | string | Optional. 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
| Reason | Use it when |
|---|---|
| allergen_wrong | An allergen is missing or listed wrongly. Safety report. |
| diet_tag_wrong | A diet tag such as Vegan or Gluten-Free does not fit the recipe. Safety report. |
| ingredient_wrong | An ingredient or a quantity is wrong or missing. |
| instructions_wrong | A step is wrong, missing or unclear. |
| time_wrong | The prep, cook or total time is wrong. |
| nutrition_wrong | A nutrition value looks wrong. |
| title_or_image_wrong | The title or the photo does not match the dish. |
| not_a_real_dish | The dish does not exist, or is not what it claims to be. |
| inappropriate | Offensive or unsuitable content. |
| other | Anything 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_exceededwith aRetry-Afterheader. - • 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.
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
| Status | Code | Meaning |
|---|---|---|
| 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. | |
| 400 | invalid_report | The body is not valid. field names the field at fault and message says why; a reason problem also returns accepted_reasons. |
| 401 | missing_api_key, invalid_api_key | No API key, or an unknown one. |
| 403 | customer_key_required | The request used a server credential rather than a customer API key. Reports are filed and limited per customer key. |
| 404 | recipe_not_found | No published recipe has this id. |
| 429 | report_limit_exceeded | This 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. |
| 500 | report_not_saved | The report could not be stored right now. Retry later. |
{
"report_id": "5d0c7e8a-1f2b-4c3d-9e4f-6a7b8c9d0e1f",
"status": "received",
"duplicate": false
}
{
"report_id": "5d0c7e8a-1f2b-4c3d-9e4f-6a7b8c9d0e1f",
"status": "received",
"duplicate": true
}
{
"error": "Invalid report",
"code": "invalid_report",
"field": "comment",
"message": "comment is required when reasons includes 'other' ..."
}
{
"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
}
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… | Endpoint | Why |
|---|---|---|
| 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.
/api/ingredients/search
Hobby+
1 credit
Search Ingredients
Search through 340,000+ ingredients from our curated ingredient database. Supports filtering by type (ingredients vs branded products).
| Parameter | Type | Description |
|---|---|---|
| q Required | stringRequired | Search query (e.g., "chicken", "tomato") |
| limit | integer | Results per page (default: 20, max: 100) |
| offset | integer | Pagination offset (default: 0) |
| filter | string | Filter type: "all", "ingredients", or "branded" (default: all) |
curl -X GET "https://api.foodashi.com/api/ingredients/search?q=chicken&limit=5" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| q | stringRequired | Search query (min 2 chars). |
| limit | integer | Max results (default: 10, max: 20). |
curl -X GET "https://api.foodashi.com/api/ingredients/autocomplete?q=red%20onion" \ -H "X-Api-Key: YOUR_API_KEY"
{
"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
}
/api/ingredients/food-groups
Hobby+
1 credit
List Food Groups
Get all food groups with ingredient counts. Useful for building category navigation.
curl -X GET "https://api.foodashi.com/api/ingredients/food-groups" \ -H "X-Api-Key: YOUR_API_KEY"
/api/ingredients/:id
Indie+
1 credit
Ingredient Details
Get detailed nutrition information for a specific ingredient including macros, vitamins, minerals, and available portion sizes.
| Parameter | Type | Description |
|---|---|---|
| :id | uuidRequired | Ingredient UUID from search results |
{
"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 field | Type | Description |
|---|---|---|
| source | string | Where the served values came from, e.g. "USDA SR Legacy". When several databases contribute it reads "Blended: A + B". |
| license | string | The licence of those values, or "Multiple (see sources)" for a blend. |
| license_url | stringnull | The licence text; null for a blend (each source has its own). |
| attribution_required | boolean | true when at least one source asks for a credit when you show its data. |
| sources | array | One 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.
/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).
| Parameter | Type | Description |
|---|---|---|
| :barcode | stringRequired | GTIN-8, UPC-A (12 digits), EAN-13 or GTIN-14, with a valid check digit |
curl -X GET "https://api.foodashi.com/api/barcode/3017620422003" \ -H "X-Api-Key: YOUR_API_KEY"
{
"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 field | Type | Description |
|---|---|---|
| image_url | stringnull | Open Food Facts product photo (front of pack, ~400px), served unmodified from images.openfoodfacts.org. |
| image_small_url | stringnull | 200px thumbnail variant of image_url. |
| image_license | stringnull | Always "CC BY-SA 3.0" when an image exists, otherwise null. |
| image_attribution | stringnull | Always "Open Food Facts" when an image exists, otherwise null. |
| image_source | stringnull | Open 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 field | Type | Description |
|---|---|---|
| source | string | Always "openfoodfacts". |
| attribution | string | The credit line: "Data from Open Food Facts (ODbL)". |
| attribution_url | string | Open Food Facts home page, to link the credit to. |
| license | string | Licence of the product data: "ODbL-1.0". |
| license_url | string | The licence text. |
| product_url | string | This product’s page on Open Food Facts. |
| data_origin | string | "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.
/api/ingredients/:id/convert
Indie+
1 credit
Unit Conversion
Convert between different units for a specific ingredient using real portion data.
| Parameter | Type | Description |
|---|---|---|
| :id | uuidRequired | Ingredient UUID |
| amount | numberRequired | Amount to convert |
| from_unit | stringRequired | Source unit (e.g., "cup", "tbsp") |
| to_unit | stringRequired | Target unit (e.g., "g", "ml") |
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"
/api/ingredients/:id/substitutes
Indie+
1 credit
Ingredient Substitutes
Find nutritionally similar substitutes for an ingredient based on food group and macro profile.
| Parameter | Type | Description |
|---|---|---|
| :id | uuidRequired | Ingredient UUID from search results |
curl -X GET "https://api.foodashi.com/api/ingredients/{id}/substitutes" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| :id | uuidRequired | Ingredient canonical UUID (from autocomplete or search). |
| random | boolean | Shuffle the matched recipes — see browse conventions. |
| page | integer | Page number (default: 1). |
| limit | integer | Results 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.
curl -X GET "https://api.foodashi.com/api/ingredients/d642a69d-3c98-4c55-83a5-f231cde9eebd/recipes?limit=10" \ -H "X-Api-Key: YOUR_API_KEY"
{
"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
400if:idis not a valid UUID. - • Returns
200with emptyrecipesarray when no matches (not a 404).
/api/ingredients/:id/allergens
Indie+
1 credit
Ingredient Allergen Check
Check which EU-14 allergens an ingredient contains or may contain.
curl -X GET "https://api.foodashi.com/api/ingredients/{id}/allergens" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| group | stringRequired | Category name (e.g. Produce, Dairy) OR USDA numeric code (e.g. 11). Discover available groups via /api/ingredients/food-groups. |
| random | boolean | Shuffle — see browse conventions. |
| page | integer | Page number (default: 1). |
| limit | integer | Results per page (default: 20, max: 100). |
curl -X GET "https://api.foodashi.com/api/ingredients/by-food-group?group=Produce&limit=20" \ -H "X-Api-Key: YOUR_API_KEY"
curl -X GET "https://api.foodashi.com/api/ingredients/by-food-group?group=11&limit=20" \ -H "X-Api-Key: YOUR_API_KEY"
/api/ingredients/:id/portions
Indie+
1 credit
Ingredient Portions
Get all available portion sizes for an ingredient with gram weight equivalents.
curl -X GET "https://api.foodashi.com/api/ingredients/{id}/portions" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
| Parameter | Type | Description |
|---|---|---|
| ingredient or name or q Required | string | Ingredient name (e.g. "butter", "egg", "buttermilk"). Case-insensitive; partial matches accepted. All three parameter names are accepted — use whichever fits your code style. |
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"
/api/ingredients/semantic-search
Pro+
2 credits
Semantic Ingredient Search
Find ingredients by meaning, not just keywords. Powered by vector embeddings — handles synonyms, regional spellings, and culinary equivalents. Searching "cilantro" finds "coriander leaf"; "shrimp" finds "prawn". Useful for cross-locale recipe matching.
| Parameter | Type | Description |
|---|---|---|
| q Required | string | Natural-language ingredient query (e.g. "green peppers used in mexican food"). |
| limit | integer | Max results (default 10, max 50). |
| min_similarity | float | Cosine similarity threshold 0.0–1.0 (default 0.5). |
curl -X GET "https://api.foodashi.com/api/ingredients/semantic-search?q=fish%20sauce%20alternative&limit=5" \ -H "X-Api-Key: YOUR_API_KEY"
/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 Field | Type | Description |
|---|---|---|
| recipe_id Required | uuid | Recipe UUID from /api/recipes or /api/search. |
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
{
"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.
/api/ingredients/batch
Pro+
5 credits
Batch Ingredient Lookup
Look up multiple ingredients at once. Much faster than individual searches for recipes.
{
"ingredients": ["chicken", "rice", "tomato"]
}
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.
/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.
| Parameter | Type | Description |
|---|---|---|
| nutrient | stringRequired | Nutrient name (e.g., "protein", "iron", "vitamin_c") |
| min | number | Minimum amount per 100g |
| max | number | Maximum amount per 100g |
| limit | integer | Results per page (default: 20, max: 100) |
curl -X GET "https://api.foodashi.com/api/ingredients/by-nutrient?nutrient=protein&min=20" \ -H "X-Api-Key: YOUR_API_KEY"
/api/ingredients/compare
Pro+
2 credits
Compare Ingredients
Side-by-side nutritional comparison of 2-5 ingredients per 100g.
| Parameter | Type | Description |
|---|---|---|
| ids | stringRequired | Comma-separated ingredient UUIDs (2-5 IDs) |
curl -X GET "https://api.foodashi.com/api/ingredients/compare?ids=uuid1,uuid2" \ -H "X-Api-Key: YOUR_API_KEY"
/api/nutrition/nutrients
Hobby+
1 credit
Nutrient List
Get all tracked nutrients with their units and categories (macros, vitamins, minerals, etc.).
curl -X GET "https://api.foodashi.com/api/nutrition/nutrients" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
curl -X GET "https://api.foodashi.com/api/nutrition/daily-values" \ -H "X-Api-Key: YOUR_API_KEY"
/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 Field | Type | Description |
|---|---|---|
| age | integer | Age in years (1–120). Optional. |
| weight_kg | number | Body weight in kilograms (2–500). Optional. Use weight_lb for pounds instead. |
| height_cm | number | Height in centimetres (50–260). Optional. Use height_in for inches instead. |
| sex | string | "male", "female", or "unspecified". Optional. |
| activity_level | string | "sedentary", "light", "moderate", "active", or "very_active". Optional. |
| goal | string | "maintain", "lose", or "gain" (default "maintain"). Optional. |
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"}'
{
"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 field | Type | Description |
|---|---|---|
| precision | string | "personalized" when all five core inputs were supplied, otherwise "estimated". |
| estimated | boolean | true when one or more inputs were defaulted. The output is always an estimate regardless. |
| bmr_kcal | integer | Basal metabolic rate from the Mifflin-St Jeor equation. |
| tdee_kcal | integer | Total daily energy expenditure (BMR × activity factor). |
| target_kcal | integer | Calorie target after applying the goal adjustment. |
| macros | object | Daily protein, fat, and carbohydrate targets in grams. |
| targets.fiber_g | integer | Daily fiber minimum in grams (eat at least this; 14 g per 1,000 kcal). |
| targets.saturated_fat_max_g | integer | Saturated fat upper limit in grams (stay under; ~10% of calories). |
| targets.added_sugars_max_g | integer | Added sugars upper limit in grams (stay under; ~10% of calories). |
| targets.sodium_max_mg | integer | Sodium upper limit in milligrams. Fixed FDA upper reference (2,300 mg/day); not personalized. |
| targets_note | string | Plain-language explanation that fiber is a minimum, saturated fat and added sugars are limits, and sodium is the fixed FDA reference (not personalized). |
| inputs_used | object | The effective inputs (including any defaults) used for the calculation, plus a human-readable activity_label. |
| assumptions | array | One entry per defaulted field, naming the field and the value assumed. Empty when fully personalized. |
| disclaimer | string | Always 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.
/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 Field | Type | Description |
|---|---|---|
| ingredients | arrayRequired | 1 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. |
| servings | number | Defaults to 1. Divides the total into per-serving figures. |
| steps | array | Optional 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. |
| title | string | Optional dish name. Helps NutriMetric pick the right category. |
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.
/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 Field | Type | Description |
|---|---|---|
| nutrition_per_serving | objectRequired | Pre-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_size | string | Human-readable serving size, e.g. "2/3 cup (55g)" |
| servings_per_container | integer | Servings per container/recipe |
| format | string | "fda" or "eu" (default: "fda") |
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"}'
/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 Field | Type | Description |
|---|---|---|
| nutrition_per_100g | objectRequired | Nutrients 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). |
| category | string | "main", "beverage", "soup", "salad", "dessert", or "snack" (auto-detected from nutrient profile if omitted) |
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"}'
/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 Field | Type | Description |
|---|---|---|
| text | stringRequired | Free 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. |
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"}'
{
"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 field | Type | Description |
|---|---|---|
| items | array | One 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). |
| nutrition | object | The 8 nutrients per item: energy_kcal, protein, total_fat, carbohydrate, sodium, fiber, saturated_fat, sugars_total. |
| total | object | The same 8 nutrients, summed across all items. |
| item_count | integer | Number of parsed items. |
| unresolved | array | Foods that could not be matched, returned honestly. |
| confidence | number | Aggregate 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.
/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.
| Parameter | Type | Description |
|---|---|---|
| amount | numberRequired | Amount to convert |
| from | stringRequired | Source unit (e.g., "cup", "tbsp", "oz") |
| to | string | Target unit (default: "g") |
| ingredient | string | Ingredient for density-adjusted conversion (e.g., "flour", "sugar") |
curl -X GET "https://api.foodashi.com/api/convert?amount=1&from=cup&to=g&ingredient=flour" \ -H "X-Api-Key: YOUR_API_KEY"
/api/allergens
Hobby+
1 credit
Allergen List
Complete list of EU 14 regulated allergens plus extended allergens, with EU regulation metadata.
curl -X GET "https://api.foodashi.com/api/allergens" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
curl -X GET "https://api.foodashi.com/api/diets" \ -H "X-Api-Key: YOUR_API_KEY"
/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.
curl -X GET "https://api.foodashi.com/api/cuisines" \ -H "X-Api-Key: YOUR_API_KEY"
/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
| Field | Type | Description |
|---|---|---|
| text RequiredRequired | string | Raw recipe text (blog post, pasted instructions, typed). Min 20 characters. |
| servings | integer | Override 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 -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.
/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
| Field | Type | Description |
|---|---|---|
| url RequiredRequired | string | Full URL to a recipe page (http/https). |
| servings | integer | Override detected servings count. |
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.
/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
| Field | Type | Description |
|---|---|---|
| image Required | string | Base64-encoded image (supports data URI). Max 4MB. Provide image OR image_url. |
| image_url | string | URL to fetch the image from (JPEG, PNG, WebP, GIF). |
| include_recipes | boolean | Include matching recipes from database (default: true). |
| max_results | integer | Max recipe matches to return (default: 5, max: 10). |
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.
/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
| Field | Type | Description |
|---|---|---|
| image Required | string | Base64-encoded image. Provide image OR image_url. |
| image_url | string | URL to fetch the image from (JPEG, PNG, WebP, GIF). |
| include_recipes | boolean | Include recipe suggestions using detected ingredients (default: true). |
| max_results | integer | Max recipe suggestions (default: 5, max: 10). |
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"}'
/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)
| Field | Type | Description |
|---|---|---|
| dish | string | Dish name (e.g., "Pad Thai", "Feijoada"). |
| ingredients | string[] | Ingredient list — AI identifies the likely dish first. |
| image | string | Base64-encoded food photo. Provide image OR image_url. |
| image_url | string | URL to a food photo (JPEG, PNG, WebP, GIF). |
| recipe_id | string | UUID of a published recipe in the database. |
Optional Preferences
| Field | Type | Description |
|---|---|---|
| preferences.no_alcohol | boolean | Only return non-alcoholic beverages. |
| preferences.budget | string | "low", "medium", or "high" — affects price range of suggestions. |
| preferences.style | string | "casual" or "fine-dining" — affects formality of recommendations. |
Response
Returns 5 beverage categories with specific names, reasoning, and serving details.
| Field | Description |
|---|---|
| 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_note | Overarching pairing philosophy for the dish. |
| confidence | 0.0–1.0 confidence score for the pairing. |
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 -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"}}'
/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
| Field | Type | Description |
|---|---|---|
| days | integer | Plan duration, 1-14 (default: 7). |
| goal | string | maintain, lose_weight, gain_weight, or build_muscle. |
| calories_per_day | integer | Override calorie target (auto-set by goal if omitted). |
| dietary_restrictions | string[] | Array of dietary tags: ["Dairy-Free", "Gluten-Free"] |
| allergen_exclusions | string[] | EU 14 allergens to exclude: ["Peanuts", "Tree Nuts"] |
| cuisine_preferences | string[] | Preferred cuisines: ["Japanese", "Italian"] |
| meals_per_day | string[] | Meal types: ["breakfast","lunch","dinner"] (also: snack, brunch). |
| servings | integer | Servings per meal (default: 2). |
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 }'
/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
| Field | Type | Description |
|---|---|---|
| planRequired | object | The plan object from /api/meal-plan/generate response. |
| actionRequired | string | swap, regenerate_day, or regenerate_meal. |
| day_indexRequired | integer | 0-based day index to modify. |
| meal_index | integer | 0-based meal index (required for swap and regenerate_meal). |
| swap_recipe_id | uuid | Recipe ID to swap in (required for swap action). |
| reason | string | Optional context for AI regeneration. |
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"}'
/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
| Parameter | Type | Description |
|---|---|---|
| goal | string | Filter by goal: lose_weight, maintain, gain_weight, build_muscle. |
curl -X GET "https://api.foodashi.com/api/meal-plan/templates?goal=lose_weight" \ -H "X-Api-Key: YOUR_API_KEY"
/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 -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"}'
/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 -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.
/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 -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.
/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 -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"}'
{
"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
}
}
/stats
API Stats
Get aggregated statistics about the recipe database including counts by cuisine, dietary tags, allergens, equipment, and NutriMetric grades.
{
"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.declarationis an object (contains,may_containwith areasonfor each,hidden_sources), never a sentence, ornull. Render your own wording from it.ingredients[].quantityis a number (fractions as decimals, such as0.5),""when the line gives no amount, ornullfor an unresolved line. It is never0for an unknown amount.ingredients[].gram_weightis the edible grams the nutrition is computed on;purchase_gram_weightis the mass of the quantity as written, to buy (bone-in, shell-on, undrained), and equalsgram_weightwhen nothing is removed before eating. Use it for shopping lists.steps[].temperatureis{value, unit}(unitiscorf; a range addsmax_value) ornull, and a freezer temperature keeps its sign (-18); a heat word such asmediumis inheat_level, never turned into a number.taste_profilescores each of the six tastes from 1 to 10.- Nutrient values can be
nullwhen a value is unknown, which is different from0.
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.
| Field | Meaning |
|---|---|
| prep_time_minutes | Hands-on preparation. |
| cook_time_minutes | All cooking time, attended or not: a two-hour oven roast counts in full. |
| rest_time_minutes | The unattended wait: marinating, chilling, proving, fermenting, curing. You are not in the kitchen for this. |
| active_time_minutes | Prep 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_minutes | prep + 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_preparation | true 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_minutes | Minutes 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_minutes | Minutes 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"
Paid Fields
Two recipe fields are included from the Indie plan: nutrimetric (the A to F NutriMetric grade) and beverage_pairing. They appear on every full recipe object (/api/recipes, /api/recipes/details, /api/random, /api/bulk-lookup, /api/similar) and beverage_pairing also on /api/recipes/:id/beverages.
| Who is calling | What the paid fields contain |
|---|---|
| Indie, Pro and Enterprise keys | The values, as in the Response Schema. No field_plans. |
| Hobby keys, in your app | A locked marker in place of each value (below). Never null and never {}, so your app can tell “not on this plan” apart from missing data. |
| The Test Kitchen, on every plan | The full values, plus a field_plans object naming the plan that includes each paid field the object carries, so you can see everything each plan returns before you choose one. |
{
"id": "a1b2c3d4-e5f6-...",
"title": "Caldo de Res",
...
"nutrimetric": {
"locked": true,
"available_on": "indie",
"message": "Available on the Indie plan and above"
},
"beverage_pairing": {
"locked": true,
"available_on": "indie",
"message": "Available on the Indie plan and above"
}
}
{
"id": "a1b2c3d4-e5f6-...",
"title": "Caldo de Res",
...
"nutrimetric": { "grade": "B", "score": 68, ... },
"beverage_pairing": { "wine": [ ... ], ... },
"field_plans": {
"nutrimetric": "indie",
"beverage_pairing": "indie"
}
}
Check locked === true before reading a paid field, and show your own upgrade hint or hide the element. available_on is the lowest plan that includes the field and message is ready to display. field_plans only appears in Test Kitchen responses, so production code should not depend on it.
Available Cuisines (78)
East Asia
Southeast Asia
South & Central Asia
Middle East
North Africa
Europe
Nordic
North America
South America
Caribbean
Pacific
Sub-Saharan Africa
Meal Types
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).
Kitchen Equipment (125)
Filter recipes by required kitchen equipment. Equipment is auto-detected from recipe instructions across all 80 world cuisines.
Pots & Pans
Bakeware
Appliances
Knives & Cutting
Prep Tools
Measuring
World Cuisine Specialty
Changelog
What's new in the Foodashi API. We ship data-quality and capability improvements continuously.
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.
No entries match your search.
2026 9 releases
v5.8 Latest 13 October 2026 #
- Added
purchase_gram_weighton every ingredient line: the mass to buy (bone-in, shell-on, undrained), besidegram_weight, the edible grams the nutrition is computed on. Scale lines addscaled_purchase_gram_weight. Additive, no version change. - Fixed The OpenAPI document and the examples now describe the recipe object exactly as served:
allergen_declaration.declarationis an object, ingredient quantities are numbers,steps[].temperatureis{value, unit}ornullwithheat_levelbeside it, taste scores run 1 to 10, and unknown values are typed asnull(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
503with codeservice_unavailableand"retryable": trueinstead 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 withcountabove 1 leaves out a recipe that cannot be read and says so with"partial": trueandfailed_ids. - Fixed When your account’s quota or extra-usage check cannot answer, every metered endpoint now answers
503with codeservice_unavailableand"retryable": trueand serves nothing. Such a call used to be served without being counted, or refused as over quota. Retry the request. Errors - Fixed
429 overage_depletednow means your prepaid extra usage really cannot pay for the call. A balance check that does not answer is a503, 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_limitedwith"limit": 120and aRetry-Afterin seconds. They used to answerquota_exceededwith aRetry-Afterat the end of the month. Rate limits - Fixed By ingredients:
exclude=eggnow leaves out every recipe that holds egg; it used to miss most of them. A term that cannot be read is a503. - Fixed Analyze text, analyze URL and meal logging answer
503service_unavailablewhen 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": truewitherrors, so an emptymatched_recipeson 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, never0: ingredient details and batch (nutrition_per_100g), barcode (nutrition, each gap named innutrition_gaps) and ad hoc analysis (each line and every total it enters). A measured0stays0. Shape change: if your code adds these values up, treatnullas unknown. - Fixed Every
/api/recipes/by-*endpoint now readsexclude_allergens,exclude_algandallergenalike, and refuses a parameter name it does not read with400 unknown_parameter(listingaccepted_parameters). A misspelt or alias allergen filter used to be ignored, so the page kept the recipes it should have excluded./api/recipes/by-ingredientsnow applies the shared browse filters too. Browse conventions - Fixed Ad hoc analysis weighs mass units only (
g,kg,mg,lb,ozand their spellings). A volume or piece unit, or an amount that is not a number from 0, is refused with400 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
servingscounts the recipe's own servings, and totals are never capped. Meal servings must be 1 to 100, or the request is refused with400 invalid_parameter. - Fixed Daily needs refuses inputs outside what its equation describes with a
400instead of a negative or empty target, and nutrition calculate answers422when no matched food has nutrient data instead of a200with 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: Bearerand readX-API-Version, theX-RateLimit-*andX-Monthly-*headers,X-Overage-Active,X-Request-Cost,X-Foodashi-Warning,X-Edge-CacheandRetry-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
equipmentnow 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_pairingalways carries the same six lists (wine,beer,cocktails,non_alcoholic,spirits,recommendations), empty when there is nothing of that kind, or isnullwhen a recipe has no pairing. - Added
untimed_minutesandoverlap_minuteson 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
temperatureas{value, unit}instead ofnull. - 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:
nutrimetricandbeverage_pairingare now{"locked": true, "available_on": "indie", "message": "..."}instead ofnullor{}. If your Hobby app checked fornull, checklockedinstead. Paid plans are unchanged. Paid Fields - Improved The Test Kitchen now shows every field on every plan, with a
field_plansobject 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/textand/api/analyze/urlnow return the climate footprint of the recipe you send, in the samesustainabilityshape. No extra credits. - Improved Every recipe sub-resource (nutrition, taste, allergens, sustainability, beverages, medical, scale) now includes
title_englishbeside the nativetitle, and answers errors with acode(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) andmeal_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).