Recipes
The Recipe API calculates environmental impact data for dishes, meals, and complete menus. Each recipe returns CO2 values, nutritional ratings, and eligibility for the Eaternity Award.
Overview
Use the Recipe API to:
- Calculate CO2 footprint for individual dishes
- Batch-process entire menus for environmental analysis
- Track recipe sustainability over time
- Earn the Eaternity Award for low-impact recipes
- Get nutritional quality ratings (A-E scale)
- Analyze ingredient-level environmental contributions
Recipe ID Uniqueness
For every time a recipe is offered in a kitchen, a new ID must be used. A recipe is uniquely identified by the combination of its id, kitchen-id, and date.
Example 1:
Your business runs Kitchen A and Kitchen B. On the 1st of April, both kitchens offer pumpkin risotto, using the same ingredients. You will have to create two different recipes with two different IDs.
Example 2:
Your business runs Kitchen A and Kitchen B. On the 1st of April, both kitchens offer pumpkin risotto. On the 2nd of April, Kitchen A offers pumpkin risotto again. You will have to create three different recipes with three different IDs.
Sub-Recipes
Recipes can reference other recipes as ingredients using the type: "recipes" ingredient field. This enables hierarchical composition of menu items from reusable sub-recipes.
All individual recipes may contain the identical sub-recipe (e.g., pumpkin risotto) as an ingredient, using the same ID each time. The sub-recipe will be stored only once in the database.
The drawback of reusing the same ID for a sub-recipe is that you will not be able to change its composition individually without impacting all recipes that reference it. Consider using individual IDs for sub-recipes if you need independent modification.
Important: Always use the transient: true flag for sub-recipes. Sub-recipes marked as transient will not be included in the monthly summary on their own — they only contribute when referenced by a non-transient parent recipe.
Query Parameters
All recipe endpoints support the following query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
full-resource | boolean | false | Return complete JSON response with all fields (except indicators). Saves bandwidth when false. |
indicators | boolean | false | Include additional environmental indicators: Vita Score, water footprint, rainforest impact, animal welfare, seasonality, local sourcing. |
nutrient-values | boolean | false | Include nutrient-values-estimated-per-specified-amount for each ingredient without requiring the full indicators response. |
ingredients-declaration | boolean | false | Include parsed ingredients-declaration data for each ingredient. |
return-uids | boolean | false | Include internal uid fields in response. Useful for tracking internal identifiers. |
transient | boolean | false | Recipe is calculated but not permanently stored — it will not appear in reports or statistics. See Transient Recipes for the distinction with the body field. |
Examples
# Get recipe with all indicators
curl "https://co2.eaternity.ch/api/recipes/{kitchen_id}/{recipe_id}?indicators=true" \
-u YOUR_API_KEY:
# Calculate recipe without permanently storing it (transient)
curl -X POST "https://co2.eaternity.ch/api/recipes/{kitchen_id}?transient=true" \
-u YOUR_API_KEY: \
-H "Content-Type: application/json" \
-d '{"id": "test", "titles": [{"language": "en", "value": "Test"}], ...}'
# Get full response with internal UIDs
curl "https://co2.eaternity.ch/api/recipes/{kitchen_id}/{recipe_id}?full-resource=true&return-uids=true" \
-u YOUR_API_KEY:
Batch-Specific Parameters
The /recipes/batch endpoint supports additional parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
priority | integer | 1 | Calculation priority (0-3). Higher values are processed first. Use 0 for background jobs, 3 for real-time UI. |
Request Headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Must be application/json |
Authorization | Yes | Basic Auth with API key |
skip_calc | No | Set to true to skip environmental calculations. Useful for CRUD operations only. |
Recipe Properties
Request Schema
{
"kitchen-id": "550e8400-e29b-41d4-a716-446655440000",
"id": "recipe-001",
"titles": [
{"language": "en", "value": "Grilled Salmon with Vegetables"},
{"language": "de", "value": "Gegrillter Lachs mit Gemüse"}
],
"recipe-portions": 4,
"date": "2024-12-16",
"weight": 350,
"ingredients": [
{
"id": "salmon-filet",
"names": [
{"language": "en", "value": "Fresh Salmon Filet"}
],
"amount": 600,
"unit": "gram",
"origin": "Norway",
"transport": "air",
"production": "aquaculture",
"conservation": "fresh",
"packaging": "plastic-tray"
}
]
}
Property Definitions
Request Properties
| Property | Type | Required | Description |
|---|---|---|---|
kitchen-id | String | Yes | The ID of the kitchen the recipe belongs to |
id | String | Yes | Unique recipe identifier. See Recipe ID Uniqueness for rules. |
titles | Array | Yes | Recipe titles as array of language objects: [{"language": "en", "value": "..."}] |
recipe-portions | Float | No | Number of portions the ingredients are specified for. Defaults to 1. |
date | ISO Date | Best practice | The date the recipe is served (format: yyyy-mm-dd). |
ingredients | Array | Yes | List of ingredient objects (min 1). See Ingredients below. |
weight | Integer | No | Final weight of the recipe per portion in grams. Used to factor evaporation and cooking losses. If not provided, defaults to the sum of ingredient weights. |
author | String | No | Original author of the recipe |
location | String | No | Location where the recipe is cooked. Address or country (arbitrary format). Falls back to kitchen location. |
production-portions | Float | No | How many portions of the recipe are planned to be produced |
sold-portions | Float | No | How many portions were actually sold (consumed). Used by the forecast endpoint to predict sales. |
instructions | Array | No | Cooking instructions as array of language objects: [{"language": "en", "value": "..."}] |
menu-line-name | String | No | Descriptor for the menu line (e.g., "Fitness", "Garden Menu", "Vegan Menu") |
menu-line-id | Integer | No | Numeric identifier for the menu line |
transient | Boolean | No | When true in a batch request body, the recipe is saved but excluded from the monthly summary. Use for sub-recipes, test submissions, or any recipe you do not want in reports. See Transient Recipes. |
If no date is provided, only a rating of the recipe is returned — no full CO2 calculation is performed. Always include a date for complete environmental impact results.
Response Properties
| Property | Type | Description |
|---|---|---|
co2-value | Integer | Total CO2 emissions of the whole recipe per serving (grams CO2-eq) |
co2-value-improvement-percentage | Float | Comparison of this recipe's CO2 footprint per food unit to the average |
co2-value-reduction-value | Float | Grams of CO2 saved by serving this recipe instead of an average recipe providing the same nutritional value |
rating | String | Environmental rating (A-E scale, A is best) |
eaternity-award | Boolean | true if the recipe is climate friendly |
info-text | String | Notes on the calculated CO2 value, e.g., remarks when properties like origin or transport are estimated |
final-weight-per-portion | Float | Final weight per portion after cooking (grams) |
vita-score | String | Nutritional quality rating (A-E) |
indicators | Object | Environmental and nutritional indicators (only when indicators=true parameter is set) |
nutrient-values-estimated-per-recipe-portion | Object | Aggregated nutrient values per portion, calculated by summing all ingredient nutrients and dividing by recipe-portions (when nutrient-values=true parameter is set) |
Transient Recipes
The transient flag has two different meanings depending on where it is used:
| Context | Meaning |
|---|---|
Query parameter ?transient=true | The recipe is calculated but not permanently stored. Use for testing, preview calculations, or any recipe you do not want in reports. |
Body field "transient": true (in batch requests) | The recipe is saved but excluded from the monthly summary. Use for sub-recipes, intermediate compositions, or recipes that should not appear in reports. |
The per-recipe body field transient can be set selectively per recipe inside a batch. Transient recipes only contribute to the monthly summary and kitchen statistics when they are used as sub-recipes in other recipes that are not transient. Set transient: true for sub-recipes, test submissions, or any recipe you do not want included in reports.
Batch Operations
Process multiple recipes in a single request for optimal performance.
Request
POST /recipes/batch
Content-Type: application/json
Authorization: Basic {api_key}
Request ID Tracking
Each recipe in a batch can include an integer request-id field to help you track recipes in the response. This is especially useful when you do not use your own recipe IDs.
- Either a
request-idor a recipeidis required per entry - The
request-iddiffers from the recipeidand has just the lifetime of a single request (not stored on the server)
Sub-Recipe Composition Example
In the following request, one menu item "Fitness Risotto" contains a single recipe "Mushroom gravy on pumpkin risotto". This recipe is again composed of two sub-recipes: "pumpkin risotto" and "Mushroom gravy". All recipes are included in the batch.
The menu item is marked as not transient ("transient": false), meaning it will be included in the monthly summary. The sub-recipes are transient ("transient": true), meaning they will only be stored for reference but not counted individually in the summary.
[
{
"request-id": 0,
"recipe": {
"id": "internal-recipe-id3",
"transient": true,
"kitchen-id": "kitchen-restaurant-a",
"titles": [
{"language": "en", "value": "Mushroom gravy on pumpkin risotto"}
],
"recipe-portions": 1,
"ingredients": [
{
"id": "internal-recipe-id1",
"type": "recipes",
"amount": 250,
"unit": "gram"
},
{
"id": "internal-recipe-id2",
"type": "recipes",
"amount": 50,
"unit": "gram"
}
]
}
},
{
"request-id": 1,
"recipe": {
"id": "internal-recipe-id1",
"transient": true,
"kitchen-id": "kitchen-restaurant-a",
"titles": [
{"language": "en", "value": "pumpkin risotto"}
],
"recipe-portions": 100,
"ingredients": [
{
"id": "101",
"type": "conceptual-ingredients",
"names": [
{"language": "en", "value": "Pumpkin"}
],
"amount": 5000,
"unit": "gram",
"origin": "Italy",
"transport": "ground",
"conservation": "dried"
}
]
}
},
{
"request-id": 2,
"recipe": {
"id": "internal-recipe-id2",
"transient": true,
"kitchen-id": "kitchen-restaurant-a",
"titles": [
{"language": "en", "value": "Mushroom gravy"}
],
"recipe-portions": 5,
"ingredients": [
{
"id": "104",
"type": "conceptual-ingredients",
"names": [
{"language": "de", "value": "onions"}
],
"amount": 78,
"unit": "gram"
}
]
}
},
{
"request-id": 3,
"recipe": {
"id": "menu-id1-fitness-2016-11-28",
"kitchen-id": "kitchen-restaurant-a",
"transient": false,
"menu-line-name": "Fitness",
"menu-line-id": 1,
"titles": [
{"language": "en", "value": "Fitness Risotto"}
],
"recipe-portions": 1,
"date": "2016-11-28",
"ingredients": [
{
"id": "internal-recipe-id3",
"type": "recipes",
"amount": 288,
"unit": "gram"
}
]
}
}
]
Eaternity Award
The Eaternity Award is a label for meals that are climate friendly. A recipe receives the Eaternity Award when it achieves an "A" CO2 rating.
The eaternity-award field is a boolean returned alongside the CO2 rating:
true— the meal is climate friendly (equivalent to an "A" CO2 rating)false— the meal does not qualify
Rating System
Recipes receive an environmental rating from A (best) to E (worst).
Rating Thresholds
| Rating | CO2 per Portion | Description |
|---|---|---|
| A | ≤ 400g | Excellent - Very low environmental impact |
| B | 401-600g | Good - Low environmental impact |
| C | 601-1000g | Average - Moderate environmental impact |
| D | 1001-1500g | Below Average - High environmental impact |
| E | > 1500g | Poor - Very high environmental impact |
Ingredients
Ingredients are the building blocks of recipes and products. They are included within recipe or product requests, not as standalone resources.
Ingredient Schema
{
"id": "tomatoes-001",
"names": [
{"language": "en", "value": "Cherry Tomatoes"},
{"language": "de", "value": "Kirschtomaten"}
],
"amount": 200,
"unit": "gram",
"origin": "Italy",
"transport": "truck",
"production": "organic",
"conservation": "fresh",
"packaging": "plastic-tray",
"producer": "BioFarm AG"
}
Required Properties
| Property | Type | Required | Description |
|---|---|---|---|
id | String | Yes | Unique ingredient identifier within recipe (max 255 chars) |
names | Array | Yes | Ingredient name in at least one language, as array of language objects: [{"language": "en", "value": "..."}]. Used for database matching. |
amount | Float | Yes | Quantity of ingredient (must be > 0) |
unit | String | Yes | Measurement unit (gram or liter) |
Optional Core Properties
| Property | Type | Default | Description |
|---|---|---|---|
type | String | conceptual-ingredients | Ingredient type: conceptual-ingredients (normal ingredient) or recipes (references existing recipe as sub-recipe) |
origin | String | - | Origin of the ingredient: postal address or country |
transport | String | - | Means of transport from origin to kitchen: air or ground |
production | String | - | Production method: standard, greenhouse, organic, fair-trade, farm, wild-caught, sustainable-fish |
processing | String | - | Processing level: raw. Meat/fish: unboned, boned. Fish: skinned, beheaded, fillet. Vegetables/fruits: cut, boiled, peeled. |
conservation | String | - | Conservation method: fresh, frozen, dried, conserved, canned, boiled-down |
packaging | String | - | Packaging type: none, plastic, paper, pet, tin, alu, glas, cardboard, tetra |
producer | String | - | Producer or brand of the product. Especially important for combined products (products with multiple ingredients). |
gtin | String | - | Global Trade Item Number (barcode) for packaged products |
ingredients-declaration | String | - | Ingredient list as declared on packaged foods |
nutrient-values | Object | - | Structured nutrient values per 100g (see Reference) |
The origin, transport, production, processing, conservation, and packaging fields accept comma-separated values when multiple apply. For example: "production": "organic, fair-trade".
Ingredient Response Fields
These fields are returned for each ingredient when full-resource=true:
| Property | Type | Description |
|---|---|---|
rating | String | CO₂ rating for this ingredient (A-E). A is best, E is worst. |
co2-value | Integer | Absolute CO₂ emissions for the ingredient in grams for the specified amount |
co2-value-improvement-percentage | Float | Comparison of this ingredient's CO₂ footprint per food unit to the average |
co2-value-reduction-value | Float | Grams of CO₂ saved compared to an average product providing the same nutritional value |
bar-chart | Float | Percentage contribution of this ingredient to total recipe CO₂ (0-100%) |
foodUnit | Float | Nutritional density value |
nutrient-values-estimated-per-specified-amount | Object | Backend-estimated nutrient values for the specified amount (when nutrient-values=true is set) |
indicators | Object | Environmental indicators for this ingredient (when indicators=true is set) |
Ingredient Types
The type field determines how the ingredient is processed:
// Normal ingredient (default)
{
"id": "rice-001",
"type": "conceptual-ingredients",
"names": [{"language": "en", "value": "Arborio Rice"}],
"amount": 200,
"unit": "gram"
}
// Sub-recipe reference
{
"id": "sauce-ref",
"type": "recipes",
"names": [{"language": "en", "value": "tomato-sauce-001"}], // References existing recipe ID
"amount": 150,
"unit": "gram"
}
Units
The API only accepts two base units:
gram: For solid ingredients (food items, spices, etc.)liter: For liquid ingredients (water, milk, oil, etc.)
Always convert to grams or liters:
- 1 kg = 1000 grams
- 1 ml = 0.001 liters
- 1 oz ≈ 28.35 grams
- 1 cup ≈ 240 ml = 0.24 liters
Ingredient Matching
The API uses fuzzy matching to identify ingredients in Eaternity's database of 50,000+ entries.
How Matching Works:
- Name normalization: Removes special characters, normalizes spelling
- Database search: Searches 50,000+ ingredient entries
- Similarity scoring: Calculates match confidence (0-100%)
- Best match selection: Returns highest-confidence match
- Fallback: Uses generic category if no close match found
Improving Match Quality:
- Use specific names: "Parmesan Cheese" instead of "Cheese"
- Include preparation method: "Fresh Cherry Tomatoes" instead of "Tomatoes"
- Specify cut or form: "Beef Sirloin Steak" instead of "Beef"
- Add brand via
producerfield for packaged items
To reduce ambiguity and minimize manual follow-ups, we strongly recommend specifying certain ingredient attributes even if technically optional. These include indicators such as air-freighted, fresh, deep-frozen, dried, preserved, baked, canned, boiled, organic, Fairtrade certified, and aquaculture-sourced (for fish). Providing this data up front helps prevent incorrect assumptions and eliminates the need for iterative clarification.
Endpoints
📄️ Create or update a batch of recipes
Batch operations allow you to create, update or delete multiple recipes at once.
📄️ Delete a batch of recipes
Delete multiple recipes at once by providing a list of recipe IDs.
📄️ Create a recipe
Create a new recipe without specifying an ID (ID will be generated).
📄️ Get a recipe
Retrieve a recipe by its ID with calculated CO₂ values and indicators.
📄️ Update or create a recipe
Update an existing recipe or create a new one with the specified ID.
📄️ Delete a recipe
Delete a recipe by its ID.
📄️ Create a recipe in a kitchen
Create a new recipe associated with a specific kitchen.
📄️ Get all recipes in a kitchen
Returns a list of recipe IDs contained in this kitchen.
📄️ Get a recipe from a kitchen
Retrieve a specific recipe from a kitchen.
📄️ Create or update a recipe in a kitchen
Update or create a recipe with the specified ID in a specific kitchen.
📄️ Delete a recipe from a kitchen
Delete a specific recipe from a kitchen.