Products
A product is an article you buy or sell as a finished item: a packaged good, a ready-made component you buy in, an article from a supplier's catalogue. Its composition usually comes from the ingredient declaration on the packaging.
You store it once, under your own id, and read back its calculated footprint. A stored product can also be used in a recipe — reference it with type: "products" (see Ingredient Types).
Storing a product
PUT /products/{id}, with your own id in the URL. The response already contains the finished calculation — there is no second request to make.
{
"id": "carrot-puree-500g",
"gtin": "00123456789023",
"names": [{"language": "de", "value": "Karottenpüree"}],
"amount": 500,
"unit": "gram",
"producer": "ACME Foods",
"ingredients-declaration": "Karotten, Wasser, Salz",
"nutrient-values": {
"energy-kcal": 35,
"fat-gram": 0.2,
"protein-gram": 0.9,
"carbohydrates-gram": 7.5
}
}
The ingredients-declaration is what tells us what the product is really made of, so include it whenever the packaging has one. Without it, the product is identified from its name alone.
To upload a catalogue, use POST /products/batch. Each product is handled on its own and gets its own entry in the response, so one product that cannot be calculated does not hold up the rest. Match the entries to your request by product-id, or by the request-id you sent along.
Once uploaded, keep your local copy in step with GET /products?updated-since — see Keeping your data up to date.
Keeping your data up to date
The values we calculate are not frozen. They improve over time — an ingredient gets matched more precisely, background data is refreshed — so a product you uploaded months ago may have a better CO₂ value today.
GET /products returns the ids of your products. Add updated-since with the date of your last synchronisation, and you get back only the ones worth fetching again:
GET /products?updated-since=2026-07-01
{
"products": ["carrot-puree-500g", "tomato-sauce-400g"]
}
That is: the products you changed, the ones never calculated, and the ones whose values may have moved because something they rely on improved. Fetch each with GET /products/{id}. A product uploaded through POST /products/batch behaves in this feed exactly like one uploaded with a single PUT.
One id namespace
Products and ordinary ingredients share a single id namespace: an id is held by either a product or an ingredient, never both at once. GET /products/{id} returns whichever holds it, and the type field tells you which:
type | What holds the id |
|---|---|
products | A product. It changes only through the product endpoints. |
conceptual-ingredients | An ordinary ingredient. A recipe or supply defines it, and any recipe or supply changes it. |
A recipe or supply that sends an id modifies the ordinary ingredient at that id, never a product. To store a product under an id an ordinary ingredient already holds, set convert-ingredient-to-product=true.
Product Properties
Request Properties
| Property | Type | Required | Description |
|---|---|---|---|
id | String | Yes | Your unique product identifier |
names | Array | Yes | Product name as array of language objects: [{"language": "de", "value": "Karottenpüree"}] |
ingredients-declaration | String | Best practice | List of ingredients as declared on the packaging. Parsed to determine what the product is made of. |
nutrient-values | Object | Best practice | Nutrient values per 100g as declared on the packaging (see Reference) |
gtin | String | Best practice | Global Trade Item Number (www.gtin.info) |
amount | Float | Best practice | Amount of the product in the specified unit. Default: 100 |
unit | String | No | Unit: kg, gram, or liter. Default: gram |
producer | String | Best practice | The producer or brand of the product |
date | String | No | Production date for seasonal calculations. Format: YYYY-MM-DD |
origin | String | Best practice | Production location: postal address or country |
transport | String | Best practice | Means of transport: air or ground |
production | String | Best practice | Production method: standard, greenhouse, organic, fair-trade, farm, wild-caught, sustainable-fish |
processing | String | No | Processing level: raw, unboned, boned, skinned, beheaded, fillet, cut, boiled, peeled |
conservation | String | Best practice | Storage method: fresh, frozen, dried, conserved, canned, boiled-down |
packaging | String | No | Packaging type: none, plastic, paper, pet, tin, alu, glas, cardboard, tetra |
Response Properties
The product is returned under product, next to a statuscode that says whether it could be calculated.
| Property | Type | Description |
|---|---|---|
statuscode | Integer | 200 when the product was calculated. See Status Codes. |
message | String | Explains the statuscode when it is not 200 |
product-id | String | The id of the product this entry belongs to |
product | Object | The product and its calculated values (below) |
| Property | Type | Description |
|---|---|---|
id | String | Product identifier |
type | String | products (write-protected) or conceptual-ingredients (any recipe may overwrite it) |
names | Array | Product names as array of language objects |
co2-value | Integer | CO₂ emissions in grams CO₂e for the specified amount (see the note below) |
rating | String | CO₂ rating (A-E). A is best, E is worst. |
eaternity-award | Boolean | true if the product is climate friendly |
co2-value-improvement-percentage | Float | Comparison of this product'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 |
food-unit | Float | Nutritional value of the product for the specified amount |
amount | Float | Product amount, echoed back from your request |
unit | String | Unit of measurement |
gtin | String | Global Trade Item Number |
date | String | Production date |
info-text | String | Notes on the calculation (e.g. "No cooking date was provided.") |
ingredients | Array | The ingredients the product is made of, with their individual ratings and CO₂ values |
ingredients-declaration | String | The original ingredient declaration text (when ingredients-declaration=true is set) |
nutrient-values-estimated-per-specified-amount | Object | Backend-estimated nutrient values scaled to the specified amount (when nutrient-values=true is set) |
indicators | Object | Environmental indicators (when indicators=true is set) |
co2-value and food-unit are calculated for the amount (and unit) on your request — ten times the amount is ten times the footprint. 500 gram and 0.5 kilogram give the same result. If you send no amount, the footprint is for one kilogram.
When you instead reference the product from a recipe, it is the amount on that recipe line that scales it — the product's own amount does not carry over.
Response Example
{
"statuscode": 200,
"message": "",
"product-id": "carrot-puree-500g",
"product": {
"id": "carrot-puree-500g",
"type": "products",
"names": [{"language": "de", "value": "Karottenpüree"}],
"co2-value": 478,
"rating": "A",
"eaternity-award": true,
"co2-value-improvement-percentage": -41.0,
"co2-value-reduction-value": -140.0,
"food-unit": 0.3,
"amount": 500,
"unit": "gram",
"gtin": "00123456789023",
"info-text": "No cooking date was provided.",
"ingredients-declaration": "Karotten, Wasser, Salz",
"ingredients": [
{
"names": [{"language": "de", "value": "Karotten"}],
"amount": 100.0,
"unit": "gram",
"rating": "A",
"co2-value": 32,
"foodUnit": 0.11
}
]
}
}
Status Codes
Next to the usual status codes, products use:
| Code | Meaning | What to do |
|---|---|---|
| 612 | The product you referenced does not exist | Store the product first, then send the recipe |
| 613 | A write a product does not accept — either a recipe tried to define an ingredient under a product's id, or a product write would convert an existing ingredient | Reference the product with type: "products" instead of defining it. To convert an ingredient on purpose, add convert-ingredient-to-product=true. |
Endpoints
📄️ List products
Returns the ids of all products stored for your account.
📄️ Create or update a batch of products
Create or update many products in a single request - the recommended way to upload a product
📄️ Create or update a product
Create or update a single product. The response already contains the finished calculation, so
📄️ Get a product
Retrieve a product together with its calculated values.
📄️ Delete a product
Delete a product. Like the read, this also resolves an ordinary ingredient stored under this