GET /label/food/additive

Answers the only question the Union list actually answers: is this additive authorised in this food category, at what maximum level and under which conditions, under Regulation (EC) No 1333/2008 (Annex II — the Union list by food category — and Annex III). Maximum levels, restrictions and footnotes are served word for word, and the answer is versioned by the consolidated text in force at the queried date. The lookup is local: milliseconds, no network call and no secret.

Use it when an agent validates a recipe, a food label or an import — “may I use E 250 in heat-treated meat products, and at what level?”. See the live /catalog for the authoritative endpoint listing and price.

An additive has no status in the abstract

This is the nuance that decides whether an answer means anything. An authorisation is published for a couple: (additive, food category). There is no such thing as an “authorised additive” — only an additive authorised in a given category, at a level published for that category.

The endpoint enforces it in its own response shape:

  • with food_category → you get a verdict (authorised / not_authorised) and the authorisations[] published for that couple;
  • without food_category → there is no verdict field at all. You get authorised_in — an inventory of the categories where an authorisation exists ({ total, truncated, categories[] }, capped at 100) — and nothing more.

An inventory is not a claim. Any answer that ignores the food category is wrong, and this service refuses to produce one.

The second property to read is that the Union list is positive: a couple with no published authorisation is not_authorised at the queried date. That verdict is dated and is not a safety assessment.

x402 golden rule: the agent pays for the answer to its question. Both authorised and not_authorised are billed 200s — under a positive list, “no published authorisation for this couple at this date” is the information. So is a no-category inventory. Only requests the service cannot answer — zero or both keys, an off-template E number, an unknown additive, an unknown category code, a date before the oldest ingested version — leave the 200 range and are not billed.

Parameters

Exactly one of the two identity keys, as a query parameter.

ParameterTypeRequiredDescription
e_numberstringone of the twoE number, template E + 3 or 4 digits + optional letter and roman numeral (E 160a(i)) — validated before any lookup
namestringone of the twoExact published name of the additive
food_categorystringno (see above)Food category code as published (08.3.2); Annex III parts are exposed as III.1 to III.5
datestringnoYYYY-MM-DD — serves the consolidated version in force at that date (defaults to today)
GET /label/food/additive?e_number=E250&food_category=08.3.2
GET /label/food/additive?e_number=E250

An off-template E number is rejected before any lookup; a code outside the referential is a 400 that names where the codes come from; a date earlier than the oldest ingested version is a 400 naming the bound.

200 response — UnifiedResponse

FieldTypeDescription
verdictstringauthorised or not_authorisedpresent only when food_category was provided
additiveobjecte_number, e_number_published, name, synonyms, functional_classes, groups
food_categoryobjectcode, name, parent_code, annex — the resolved category (with a verdict only)
authorisationsobject[]One per published line covering the couple (see below); empty on not_authorised
authorised_inobjectNo-category form only: { total, truncated, categories[] }, capped at 100
versionobjectThe consolidated version served: consolidated_ref, applicable_from, applicable_to
notestringWhy the verdict reads as it does — a dated not_authorised statement, or the group resolution behind an authorised
limitsstring[]The fixed caveats carried by every response (a sixth one is added on the no-category form)

An authorisations[] entry

FieldTypeDescription
annexstringII (Union list by food category) or III
partstringPart of the Annex
max_levelstringWord for word"100", "500 mg/kg", "quantum satis"; never converted to a number
restrictionsstringRestrictions of use as published, line breaks and periods of application included
published_asstringThe wording the line is published under ("Nitrites", "Additives") when it is not the additive’s own name
footnotesobject[]{ number, text }verbatim
via_groupobjectPresent when the authorisation is published for a group rather than for the additive by name
amending_actstringThe amending regulation, with amending_celex and amending_oj_date

quantum satis is served as published, never turned into a number: it is a regulatory instruction (“no maximum level, use no more than needed”), not a missing value to be filled in.

via_group — group authorisations resolved at read time

Many authorisations are published for a group (Group I to IV, or a combined range such as E 249 - 250) rather than for the additive by name. Those are stored as published and resolved when you ask, with via_group reporting the resolution (group_name, group_key, and specific_max_level when the group line carries one). A range whose composition is not published in Part C cannot be resolved — not_authorised then means no published authorisation was found for this couple, which is exactly what it says.

Example — a verdict, with the group resolution stated

GET /label/food/additive?e_number=E250&food_category=08.3.2 — sodium nitrite in heat-treated meat products. The authorisation is published for the group E 249-250, and the response says so instead of pretending E 250 is named:

{
  "data": {
    "verdict": "authorised",
    "additive": {
      "e_number": "E250",
      "e_number_published": "E 250",
      "name": "Sodium nitrite",
      "functional_classes": ["other than colours and sweeteners"],
      "groups": ["E 249–250"]
    },
    "food_category": {
      "code": "08.3.2",
      "name": "Heat-treated meat products",
      "parent_code": "08.3",
      "annex": "II"
    },
    "authorisations": [
      {
        "annex": "II",
        "part": "E",
        "max_level": "55",
        "restrictions": "only sterilised meat products (Fo > 3,00)\nPeriod of application: from 9 October 2025",
        "published_as": "Nitrites",
        "footnotes": [
          {
            "number": "58",
            "text": "(58): Fo-value 3 is equivalent to 3 minutes heating at 121 °C (reduction of the bacterial load of one billion spores in each 1 000 cans to one spore in a thousand cans)"
          }
        ],
        "via_group": { "group_name": "E 249-250", "group_key": "E249-250" },
        "amending_act": "COMMISSION REGULATION (EU) 2023/2108 of 6 October 2023",
        "amending_celex": "32023R2108",
        "amending_oj_date": "2023-10-09"
      }
    ],
    "version": {
      "consolidated_ref": "02008R1333 — EN — 18.02.2026",
      "applicable_from": "2026-02-18",
      "applicable_to": "2026-08-18"
    },
    "note": "E 250 is not authorised by name in food category 08.3.2: the authorisation is published for the group(s) E 249 - 250, of which it is a published member. The group reference is kept as published and resolved at read time."
  },
  "provenance": {
    "source": "Regulation (EC) No 1333/2008 on food additives — consolidated text (EUR-Lex), Annex II (Union list by food category) and Annex III",
    "fetched_at": "2026-07-30T18:28:58Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-02-18T00:00:00Z" }
  }
}

The real answer carries several authorisations[] lines for this couple, each with its own period of application — the level dropped from "100" to "55" on 9 October 2025, and both lines are served with the restriction text that dates them. Reading the level without its restrictions loses the date.

Example — no food category, therefore no verdict

GET /label/food/additive?e_number=E250 returns no verdict field, only the inventory of categories where an authorisation exists:

{
  "additive": { "e_number": "E250", "name": "Sodium nitrite", "groups": ["E 249–250"] },
  "authorised_in": {
    "total": 7,
    "truncated": false,
    "categories": [
      { "code": "08.2", "name": "Meat preparations as defined by Regulation (EC) No 853/2004", "via_group": "E 249–250" },
      { "code": "08.3.1", "name": "Non-heat-treated meat products", "via_group": "E 249–250" },
      { "code": "08.3.2", "name": "Heat-treated meat products", "via_group": "E 249-250" },
      { "code": "III.3", "name": "Food additives including carriers in food enzymes" }
    ]
  }
}

The response adds a sixth limit spelling out the contract: “No verdict is issued without ‘food_category’: ‘authorised_in’ lists the food categories in which an authorisation is published for this additive, and nothing more. An additive is never ‘authorised’ as such.”

Example — not authorised is a dated, billed 200

GET /label/food/additive?e_number=E250&food_category=01.1 (milk):

{
  "verdict": "not_authorised",
  "food_category": {
    "code": "01.1",
    "name": "Unflavoured pasteurised and sterilised (including UHT) milk",
    "parent_code": "01",
    "annex": "II"
  },
  "authorisations": [],
  "note": "No authorisation is published for E 250 in food category 01.1 (Unflavoured pasteurised and sterilised (including UHT) milk) in the Union list of Regulation (EC) No 1333/2008 as in force on 2026-07-30 (consolidated version 02008R1333 — EN — 18.02.2026 of the Regulation). Under the positive list, this means the additive may not be used in that food category at that date."
}

Example — quantum satis, and an Annex III part

GET /label/food/additive?e_number=E300&food_category=01.4 (ascorbic acid) is authorised through Group I, whose level is quantum satis — served as the phrase, on the group line:

"authorisations": [
  {
    "annex": "II",
    "part": "E",
    "published_as": "Additives",
    "via_group": {
      "group_name": "Group I",
      "group_key": "GROUPI",
      "specific_max_level": "quantum satis"
    },
    "amending_act": "COMMISSION REGULATION (EU) No 1129/2011 of 11 November 2011"
  }
]

Annex III parts are queried with the same key shape (food_category=III.3Food additives including carriers in food enzymes), and answer with "annex": "III" and the level published there ("max_level": "500 mg/kg").

What this endpoint refuses to do

The limits are content, not a footer:

  • an additive has no status in the abstract — an authorisation is a couple, and any answer ignoring the food category is wrong;
  • the Union list is positive: not_authorised is dated and is not a safety assessment;
  • levels, restrictions and footnotes are served exactly as published (quantum satis included);
  • group authorisations are stored as published and resolved at read time with via_group; an unpublished composition is not expanded;
  • out of scope: flavourings (Regulation (EC) No 1334/2008), food enzymes (No 1332/2008), novel foods, allergen labelling, the nutrition declaration, acceptable daily intakes, and the level of an additive in a finished product (no dose computation, no cumulation).

Freshness

Answers are served from a snapshot of the consolidated Regulation, dated by the version in force at the queried date. A missed refresh keeps serving the last good snapshot, honestly dated by freshness.as_of, and never becomes a 5xx.

Errors

Only requests the service cannot answer leave the 200 range — none of them are billed.

StatuscodeCase
400INVALID_INPUTZero or both identity keys; an off-template E number; an unknown or empty food_category; a date before the oldest ingested version
404NOT_FOUNDThe additive is absent from the Union list (Annexes II and III)
503DATA_UNAVAILABLEThe food-additives dataset has not been ingested yet
500INTERNALInternal error (detail logged, not exposed)
{ "error": "provide exactly one of 'e_number' or 'name'", "code": "INVALID_INPUT" }
{ "error": "invalid E number format: 'E25' (expected E followed by 3 or 4 digits, an optional letter and an optional roman numeral, e.g. 'E 160a(i)')", "code": "INVALID_INPUT" }
{ "error": "unknown food category code: '99.9' (use a category code as published in Annex II Part D of Regulation (EC) No 1333/2008, e.g. '08.3.2')", "code": "INVALID_INPUT" }
{ "error": "food additive not found in the Union list of Regulation (EC) No 1333/2008 (Annexes II and III)", "code": "NOT_FOUND" }

An unknown additive is a 404 (there is nothing to answer about); a known additive with no authorisation in the requested category is a billed 200 not_authorised. The two are never confused.

Attribution

Verdicts are derived from Regulation (EC) No 1333/2008 on food additives, consolidated text published on EUR-Lex (European Union) — Annex II (the Union list by food category) and Annex III.

See also