Aller au contenu principal

Recettes

La Recipe API calcule l'empreinte environnementale de plats, de repas et de menus complets. Chaque recette renvoie des valeurs de CO2, des notations nutritionnelles et l'éligibilité à l'Eaternity Award.

Pour des exemples complets de request et de response, voir les use cases Évaluation de l'empreinte d'une recette et Menus pour l'affichage du plan de menus et les rapports.

Aperçu​

Utilisez la Recipe API pour :

  • Calculer l'empreinte CO2 de plats individuels
  • Traiter des menus entiers par lot pour une analyse environnementale
  • Suivre la durabilité des recettes dans le temps
  • Obtenir l'Eaternity Award pour les recettes à faible empreinte
  • Obtenir des notations de qualité nutritionnelle (échelle A-E)
  • Analyser la contribution environnementale de chaque ingrédient

Unicité de l'ID de recette​

L'API identifie une recette uniquement par son id. Le kitchen-id et la date sont enregistrés avec la recette, mais ils n'en font pas une autre recette.

Si vous envoyez une recette avec un id qui existe déjà, l'API écrase la recette enregistrée, y compris son kitchen-id et sa date. Le service précédent disparaît alors de cette cuisine et de ce jour.

La règle : utilisez un nouvel id chaque fois qu'un plat est servi dans une cuisine un jour donné.

Exemple 1 : la cuisine A et la cuisine B servent toutes deux un risotto au potiron le 1er avril. Envoyez deux recettes avec deux ids différents, par exemple risotto-kitchen-a-2026-04-01 et risotto-kitchen-b-2026-04-01. Avec un id commun, la deuxième request déplacerait le risotto vers la cuisine B, et la cuisine A le perdrait dans ses rapports.

Exemple 2 : la cuisine A sert de nouveau le risotto le 2 avril. C'est une troisième recette avec un troisième id, par exemple risotto-kitchen-a-2026-04-02. Réutiliser l'id du 1er avril déplacerait le premier service au 2 avril, et le 1er avril le perdrait.

Une manière simple d'obtenir un nouvel id à chaque fois : combinez votre propre numéro de recette avec la cuisine et la date.

Les sous-recettes font exception. Une sous-recette comme une sauce peut garder le même id dans chaque menu qui l'utilise ; voir Sous-recettes. Pour les menus envoyés par cuisine et par date, voir Menus pour l'affichage du plan de menus et les rapports.

Sous-recettes​

Une recette peut utiliser d'autres recettes comme ingrédients grâce au champ d'ingrédient type: "recipes". Cela permet de composer des plats du menu de manière hiérarchique à partir de sous-recettes réutilisables.

Toutes les recettes individuelles peuvent contenir la même sous-recette (par exemple un risotto au potiron) comme ingrédient, avec le même ID à chaque fois.

Réutilisation de l'ID d'une sous-recette

L'inconvénient de réutiliser le même ID pour une sous-recette : vous ne pouvez pas modifier sa composition individuellement sans affecter toutes les recettes qui y font référence. Utilisez des IDs individuels pour les sous-recettes si vous devez les modifier indépendamment.

Les sous-recettes sont envoyées comme transitoires : elles comptent uniquement à travers le menu qui les utilise. Voir Recettes transitoires.

Paramètres de requête​

Tous les endpoints de recettes acceptent les paramètres de requête full-resource, indicators, nutrient-values, ingredients-declaration, return-uids et transient. Valeurs et valeurs par défaut : Paramètres de requête. Pour transient, voir aussi Recettes transitoires.

Exemples​

# Get recipe with all indicators
curl "https://co2.eaternity.ch/api/kitchens/{kitchen_id}/recipes/{recipe_id}?indicators=true" \
-u YOUR_API_KEY:

# Preview: calculate a recipe without keeping it (transient)
curl -X POST "https://co2.eaternity.ch/api/kitchens/{kitchen_id}/recipes?transient=true" \
-u YOUR_API_KEY: \
-H "Content-Type: application/json" \
-d '{"recipe": {"titles": [{"language": "en", "value": "Test"}], "date": "2024-12-16", "ingredients": [...]}}'

# Get full response with internal UIDs
curl "https://co2.eaternity.ch/api/kitchens/{kitchen_id}/recipes/{recipe_id}?full-resource=true&return-uids=true" \
-u YOUR_API_KEY:

Paramètres propres au lot​

L'endpoint /recipes/batch accepte des paramètres supplémentaires :

ParamètreTypeDéfautDescription
priorityinteger1Priorité de calcul : 0 (basse) ou 1 (haute, traitée en premier). Utilisez 0 pour les tâches en arrière-plan.

En-têtes de requête​

En-têteObligatoireDescription
Content-TypeOuiDoit être application/json
AuthorizationOuiBasic Auth avec la clé API

Propriétés de la recette​

Ingrédients

Les champs de chaque ligne de ingredients sont décrits sur une page dédiée : Ingrédients.

Schéma de la request​

PUT /kitchens/kitchen-restaurant-a/recipes/recipe-001
{
"recipe": {
"kitchen-id": "kitchen-restaurant-a",
"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": "Salmon (farmed, fillet)"}],
"amount": 600,
"unit": "gram",
"origin": "Norway",
"transport": "air",
"production": "standard",
"conservation": "fresh",
"packaging": "plastic"
}
]
}
}

Response :

{
"statuscode": 200,
"message": "",
"request-id": 0,
"recipe-id": "recipe-001",
"recipe": {
"food-unit": 1.06,
"final-weight-per-portion": 350.0,
"eaternity-award": false,
"co2-value": 743,
"rating": "B",
"co2-value-improvement-percentage": 10,
"co2-value-reduction-value": 81,
"id": "recipe-001",
"kitchen-id": "kitchen-restaurant-a",
"titles": [{"language": "en", "value": "Grilled Salmon with Vegetables"}, {"language": "de", "value": "Gegrillter Lachs mit Gemüse"}],
"date": "2024-12-16",
"weight": 350.0,
"servings": 4,
"recipe-portions": 4,
"ingredients": []
}
}

Définition des propriétés​

Propriétés de la request​

PropriétéTypeObligatoireDescription
kitchen-idStringOuiID de la cuisine à laquelle appartient la recette
idStringOuiIdentifiant unique de la recette. Règles : Unicité de l'ID de recette.
titlesArrayOuiTitres de la recette, sous forme de tableau d'objets de langue : [{"language": "en", "value": "..."}]
recipe-portionsFloatNonNombre de portions pour lesquelles les ingrédients sont indiqués. Par défaut 1.
dateISO DateBonne pratiqueDate à laquelle la recette est servie (format : yyyy-mm-dd).
ingredientsArrayOuiListe d'objets ingrédient (au moins 1). Voir Ingrédients.
weightIntegerNonPoids final de la recette par portion, en grammes. Sert à tenir compte de l'évaporation et des pertes à la cuisson. S'il n'est pas fourni, il correspond par défaut à la somme des poids des ingrédients. Pour modéliser la perte d'ingrédients individuels, utilisez plutôt le champ par ingrédient loss-in-percent-of-amount.
authorStringNonAuteur original de la recette
locationStringNonLieu où la recette est cuisinée. Adresse ou pays (format libre). À défaut, la localisation de la cuisine est utilisée.
production-portionsFloatNonNombre de portions de la recette dont la production est prévue
sold-portionsFloatNonNombre de portions effectivement vendues (consommées). Utilisé par l'endpoint Forecast pour prévoir les ventes.
instructionsArrayNonInstructions de préparation, sous forme de tableau d'objets de langue : [{"language": "en", "value": "..."}]
menu-line-nameStringNonDésignation de la ligne de menu (par exemple « Fitness », « Garden Menu », « Vegan Menu »)
menu-line-idIntegerNonIdentifiant numérique de la ligne de menu
transientBooleanNonChamp de l'élément du lot, à côté de request-id. true rend la recette transitoire : calculée et renvoyée, non conservée, non comptée seule.
Comportement du champ date

Une recette sans date est calculée, mais elle manque dans les rapports basés sur la date. Indiquez toujours la date à laquelle la recette est servie.

Propriétés de la response​

PropriétéTypeDescription
co2-valueIntegerÉmissions totales de CO2 de la recette entière par portion (grammes CO2-eq)
co2-value-improvement-percentageFloatComparaison de l'empreinte CO2 de cette recette par food unit avec la moyenne
co2-value-reduction-valueFloatGrammes de CO2 économisés en servant cette recette au lieu d'une recette moyenne de même valeur nutritionnelle
ratingStringNotation environnementale (échelle A-E, A est la meilleure)
eaternity-awardBooleantrue si la recette est respectueuse du climat
info-textStringRemarques sur la valeur de CO2 calculée, par exemple lorsque des propriétés comme l'origine ou le transport sont estimées
final-weight-per-portionFloatPoids final par portion après cuisson (grammes)
indicators.vita-scoreObjectNotation de la qualité nutritionnelle (A-E) et ses facteurs de risque (uniquement avec indicators=true). Voir Vita Score.
indicatorsObjectIndicateurs environnementaux et nutritionnels (uniquement avec le paramètre indicators=true)
nutrient-values-estimated-per-recipe-portionObjectValeurs nutritionnelles agrégées par portion : somme des nutriments de tous les ingrédients divisée par recipe-portions (avec le paramètre nutrient-values=true)

Recettes transitoires​

Ce que signifie transient

Une recette transitoire est calculée, et son résultat est renvoyé dans la response. Ensuite, elle n'est pas conservée :

  • Elle ne compte jamais seule dans les rapports, même avec une date. Ses ingrédients comptent uniquement à travers le menu qui l'utilise.
  • Elle ne peut pas être récupérée plus tard. Un GET répond 404, et elle n'apparaît pas dans la liste des recettes de la cuisine.
  • Un menu peut l'utiliser comme sous-recette.

Où l'activer​

OùS'applique à
Champ du body "transient": true sur un élément du lot, à côté de request-idCette seule recette
Paramètre de requête ?transient=trueToutes les recettes de la request, menus compris

Placez le champ du body sur l'élément du lot, pas dans recipe. Dans recipe, il est ignoré et la recette est enregistrée comme une recette normale.

?transient=true sur un lot de menus rend aussi les menus transitoires : ils disparaissent alors des rapports. Pour les sous-recettes, utilisez le champ du body.

Quand l'utiliser​

  • Sous-recettes comme une sauce, un accompagnement ou une base : transitoires.
  • Aperçus et tests : ?transient=true.
  • Menus qui doivent compter dans les rapports : non transitoires.

Opérations par lot​

Traitez plusieurs recettes en une seule request pour de meilleures performances.

Request​

POST /recipes/batch
Content-Type: application/json
Authorization: Basic {api_key}

Suivi par request-id​

Chaque recette d'un lot peut inclure un champ entier request-id pour vous aider à retrouver les recettes dans la response. C'est particulièrement utile si vous n'utilisez pas vos propres IDs de recette.

  • Chaque entrée nécessite soit un request-id, soit un id de recette
  • Le request-id est différent de l'id de la recette et ne vit que le temps d'une seule request (il n'est pas enregistré sur le serveur)

Exemple de composition avec sous-recettes​

Dans la request suivante, un plat du menu « Fitness Risotto » contient une seule recette « Mushroom gravy on pumpkin risotto ». Cette recette se compose à son tour de deux sous-recettes : « pumpkin risotto » et « Mushroom gravy ». Toutes les recettes sont incluses dans le lot.

Le plat du menu n'est pas transitoire ("transient": false) : il compte donc dans les rapports. Les sous-recettes sont transitoires ("transient": true) : elles sont calculées avec le menu et comptent uniquement à travers lui. Le flag se trouve sur chaque élément du lot, à côté de request-id.

POST /recipes/batch
[
{
"request-id": 0,
"transient": true,
"recipe": {
"id": "internal-recipe-id3",
"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,
"transient": true,
"recipe": {
"id": "internal-recipe-id1",
"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,
"transient": true,
"recipe": {
"id": "internal-recipe-id2",
"kitchen-id": "kitchen-restaurant-a",
"titles": [{"language": "en", "value": "Mushroom gravy"}],
"recipe-portions": 5,
"ingredients": [
{
"id": "104",
"type": "conceptual-ingredients",
"names": [{"language": "en", "value": "onions"}],
"amount": 78,
"unit": "gram"
}
]
}
},
{
"request-id": 3,
"transient": false,
"recipe": {
"id": "menu-id1-fitness-2016-11-28",
"kitchen-id": "kitchen-restaurant-a",
"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"
}
]
}
}
]

Response, une entrée par recette dans l'ordre de la request :

[
{
"statuscode": 200,
"message": "",
"recipe-id": "internal-recipe-id3",
"request-id": 0,
"recipe": {
"food-unit": 1.36,
"final-weight-per-portion": 300.0,
"eaternity-award": false,
"co2-value": 2030,
"rating": "C",
"co2-value-improvement-percentage": -91,
"co2-value-reduction-value": -969,
"id": "internal-recipe-id3",
"kitchen-id": "kitchen-restaurant-a",
"titles": [{"language": "en", "value": "Mushroom gravy on pumpkin risotto"}],
"servings": 1,
"recipe-portions": 1,
"ingredients": []
}
},
{
"statuscode": 200,
"message": "",
"recipe-id": "internal-recipe-id1",
"request-id": 1,
"recipe": {
"food-unit": 0.26,
"final-weight-per-portion": 50.0,
"eaternity-award": false,
"co2-value": 404,
"rating": "C",
"co2-value-improvement-percentage": -98,
"co2-value-reduction-value": -200,
"id": "internal-recipe-id1",
"kitchen-id": "kitchen-restaurant-a",
"titles": [{"language": "en", "value": "pumpkin risotto"}],
"servings": 100,
"recipe-portions": 100,
"ingredients": []
}
},
{
"statuscode": 200,
"message": "",
"recipe-id": "internal-recipe-id2",
"request-id": 2,
"recipe": {
"food-unit": 0.02,
"final-weight-per-portion": 15.600000000000001,
"eaternity-award": true,
"co2-value": 3,
"rating": "A",
"co2-value-improvement-percentage": 74,
"co2-value-reduction-value": 9,
"id": "internal-recipe-id2",
"kitchen-id": "kitchen-restaurant-a",
"titles": [{"language": "en", "value": "Mushroom gravy"}],
"servings": 5,
"recipe-portions": 5,
"ingredients": []
}
},
{
"statuscode": 200,
"message": "",
"recipe-id": "menu-id1-fitness-2016-11-28",
"request-id": 3,
"recipe": {
"food-unit": 1.31,
"final-weight-per-portion": 288.0,
"eaternity-award": false,
"co2-value": 1949,
"rating": "C",
"co2-value-improvement-percentage": -91,
"co2-value-reduction-value": -931,
"id": "menu-id1-fitness-2016-11-28",
"kitchen-id": "kitchen-restaurant-a",
"titles": [{"language": "en", "value": "Fitness Risotto"}],
"date": "2016-11-28",
"servings": 1,
"recipe-portions": 1,
"ingredients": [],
"menu-line-name": "Fitness",
"menu-line-id": 1
}
}
]

Eaternity Award​

L'Eaternity Award est un label pour les repas respectueux du climat. Une recette obtient l'Eaternity Award lorsqu'elle atteint une notation CO2 « A ».

Le champ eaternity-award est un booléen renvoyé avec la notation CO2 :

  • true — le repas est respectueux du climat (équivaut à une notation CO2 « A »)
  • false — le repas ne remplit pas les conditions

Système de notation​

Les recettes reçoivent une notation environnementale de A (la meilleure) à E (la moins bonne). Seuils : Échelle de notation.


Ingrédients​

Ingrédients

Chaque ligne d'une recette est un objet ingrédient. Champs, valeurs autorisées, types et correspondance : Ingrédients.


Endpoints​