Is this exact label wording an authorised health claim?

Most of the EU claims register is refusals, not permissions. One call checks a proposed label wording against it and returns the official reason for a no.

By Matthias Begot ·

An agent reviewing packaging copy is not asking which claims exist. It is asking whether this string, the one already written on the artwork, is one of them. POST /label/claims/check answers that from the EU Register of nutrition and health claims: authorised with the exact legal wording and conditions of use, non-authorised with the full official rejection reason and the EFSA opinion behind it, a partial fragment, or absent from the register.

The reason this is worth a call rather than a prompt is arithmetic. In the register snapshot dated 1 August 2026, 2,337 entries: 269 authorised, 2,067 non-authorised, one revoked. A language model has read the authorised sentences a thousand times — they are printed on every yoghurt pot in Europe. The 2,067 refusals appear nowhere except the register, and they are the half that decides whether a pack is legal.

Every capture below was taken from production on 11 August 2026 against that snapshot.

The review direction, not the drafting direction

The same dated register is exposed through two routes, and they are not interchangeable:

EndpointInputReaches
GET /label/claims/permitteda nutrientthe 269 authorised claims — what you may write
POST /label/claims/checka wordingall 2,337 entries — including the 2,067 refusals

permitted is the drafting route, covered in Which health claims may you write on an EU label?. It hands a drafting agent the sentences it is allowed to start from, and it reports the refusals only as a count.

check is the audit route. It takes text that already exists — copy a human wrote, a translation, a legacy pack being re-registered, a sentence a model produced — and reads the register’s verdict on it. That is the only direction that can return why something is refused, and the rejection reason is the payload a reviewer actually needs.

Statuses are relayed verbatim, including values outside the two-word nomenclature. Exactly one entry in this snapshot carries REVOKED: the monacolin K from red yeast rice claim, struck from the Union list by Commission Regulation (EU) 2024/2041 after monacolins were restricted under Annex III of Regulation (EC) No 1925/2006. Folding it into non_authorised would be tidier and would erase the fact that this claim was once permitted.

Isomaltulose: EFSA said yes, the Commission said no

POST /label/claims/check with {"wording": "Isomaltulose contributes to normal energy-yielding metabolism", "nutrient": "Isomaltulose"}:

{
  "data": {
    "verdict": "non_authorised",
    "match_kind": "exact",
    "claims": [
      {
        "code": "POL-HC-11221",
        "type": "Art. 13.5",
        "status": "non_authorised",
        "nutrient": "Isomaltulose",
        "wording": "Isomaltulose contributes to normal energy-yielding metabolism",
        "rejections": [
          {
            "code": "HC_RR_166",
            "reason": "The use of such a health claim would convey a conflicting and confusing message to consumers, because it would encourage consumption of sugars for which, on the basis of generally accepted scientific advice, national and international authorities inform the consumer that their intake should be reduced."
          }
        ],
        "efsa": {
          "question": "Q-2021-00073",
          "url": "https://efsa.onlinelibrary.wiley.com/doi/epdf/10.2903/j.efsa.2021.6849"
        }
      }
    ]
  },
  "provenance": {
    "source": "EU Register on nutrition and health claims",
    "fetched_at": "2026-08-11T06:44:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-08-01T00:00:00Z" }
  }
}

This is the sentinel of the endpoint, and the reason is what makes it one. EFSA established the cause-and-effect relationship. Its 2021 opinion (EFSA Journal 2021;19(10):6849) concluded that isomaltulose contributes to normal energy-yielding metabolism — and then observed that so does every other macronutrient, so the effect is not specific to isomaltulose. The Commission refused the claim anyway, in Regulation (EU) 2024/2105 of 31 July 2024, on the ground that authorising it would encourage the consumption of sugars, contrary to Article 3 of Regulation (EC) No 1924/2006.

HC_RR_166 is used once in the whole register. There is no pattern to learn here, no scientific signal to infer, and no way to reach this answer from nutrition knowledge: the claim is true, and it is still illegal. Either you have read the register entry, or you approve the pack.

Selenium: the grammatically perfect refusal

The more common failure is quieter. Authorised claims share a house style — “X contributes to the normal function of Y” — and that style is trivially imitable. Here are two sentences about the same mineral:

"Selenium contributes to the normal function of the immune system"
"Selenium is necessary for normal cardiovascular function."

Both read like register entries. Both are register entries. One is authorised (POL-HC-6463), the other is refused (POL-HC-7918, reason HC_RR_130: “the evidence provided is insufficient to substantiate this claimed effect for this food”). Nothing in the grammar, the vocabulary or the biology separates them — only the file does.

Real label copy is a paragraph, not a sentence, so the endpoint reads it as one. Submitting both sentences as a single wording:

{
  "verdict": "non_authorised",
  "match_kind": "contains_registered",
  "claims": [
    { "code": "POL-HC-6463", "status": "authorised", "nutrient": "Selenium",
      "wording": "Selenium contributes to the normal function of the immune system",
      "conditions_of_use": "The claim may be used only for food which is at least a source of selenium …" },
    { "code": "POL-HC-7918", "status": "non_authorised", "nutrient": "Selenium",
      "wording": "Selenium is necessary for normal cardiovascular function.",
      "rejections": [ { "code": "HC_RR_130", "reason": "Non-compliance with the Regulation because on the basis of the scientific evidence assessed, the evidence provided is insufficient to substantiate this claimed effect for this food." } ] }
  ]
}

Two properties of that response are contract:

  • contains_registered — the submitted text contains whole registered claims inside a longer body of copy. That is a firm verdict, not a hedge.
  • A mixed match tips to non_authorised. One refused claim anywhere in the block sinks the block. A response that reported “authorised” because one of the two matches was fine would be the exact false positive this endpoint exists to prevent — so the whole matched list is returned, each entry with its own status, and the verdict follows the worst one.

Strict matching, and the price of it

Matching is strict-normalised and never fuzzy: case, punctuation and whitespace are folded, then the comparison is exact or word-level containment. CALCIUM IS NEEDED FOR THE MAINTENANCE OF NORMAL BONES!! matches POL-HC-6346 exactly. There is no similarity score anywhere in the response.

match_kindThe submitted wording is…
exactexactly a registered claim, once normalised
contains_registeredlonger copy that contains a whole registered claim
contained_in_registereda fragment of a longer registered claim

The cost of that discipline is real and worth stating plainly. Compare:

"Water contributes to the maintenance of normal regulation of the body's temperature"
  → authorised (POL-HC-6527)

"Water contributes to the maintenance of normal thermoregulation"
  → not_in_register

Same meaning to any reader. One is the legal wording, the other is not, and the service will not bridge the gap. That refusal is deliberate: Recital 9 of Regulation (EU) No 432/2012 does allow a wording with the same meaning for the consumer to be used — but “same meaning” is a semantic judgment about consumer perception, and a matcher that guessed at it would be manufacturing legal opinions with a string-distance function. The endpoint reports register membership; the flexibility judgment stays with a human.

Fragments get the same treatment. "maintenance of normal bones" is partial_match against eight registered claims — calcium, magnesium, manganese, phosphorus, protein, vitamin D, vitamin K, zinc — returned in full with their statuses verbatim, plus a note stating that a fragment is not itself an authorised claim. It is never a green light. Below a four-word floor the fragment stops being informative and the verdict falls back to not_in_register: "of normal bones" matches nothing.

Two ways to read the answer wrong

Scoping to the wrong nutrient hides a refusal. The optional nutrient narrows the search, which is useful — the same fragment scoped to Calcium returns one registered claim instead of eight. But scope it to a nutrient the wording is not about and the match disappears:

{ "wording": "Selenium is necessary for normal cardiovascular function.", "nutrient": "Calcium" }
  → not_in_register, with the 10 authorised Calcium claims as fallback

A refused selenium claim came back as “not in the register” with a helpful list of calcium claims attached. Nothing lied — the register holds no calcium claim with that wording — but an agent that pipes a nutrient field from upstream metadata and trusts the verdict has built a filter that quietly passes rejections. Omit nutrient when the answer must be safe; pass it only to disambiguate a fragment you already know the subject of.

Absent is not permitted. not_in_register is neither an authorisation nor a prohibition, and the note on every such response says so, naming the reason: roughly 2,000 botanical claims have sat “on hold” under the Article 13(1) transitional regime since 2012. They are not in the register and may still be in use. "Glucosamine helps maintain healthy joints" and "Water helps prevent dehydration" both come back not_in_register — for entirely different underlying reasons that the register cannot distinguish, and neither can this endpoint.

Which is the boundary of the service, stated once: it relays the register status of a wording. It does not assess whether your product meets the conditions of use, does not judge the artwork as a whole, and is not legal advice.

Billing and failure modes

All four verdicts are billed 200s — the question was well-formed and it got an answer, including when the answer is “the register does not carry this”:

CaseResult
authorised — every match is authorised200, billed
non_authorised — at least one match is refused, or carries a status outside the nomenclature200, billed
partial_match — a fragment, with the full claims it sits in200, billed
not_in_register — no match, with the nutrient’s authorised claims as fallback200, billed
wording present but empty or blank400 MISSING_PARAMETER, not billed
wording absent, or punctuation with no word in it400 INVALID_INPUT, not billed
nutrient present but empty400 INVALID_INPUT, not billed
Register not yet ingested503 DATA_UNAVAILABLE, not settled

A missed refresh keeps serving the last good snapshot under an honest provenance.freshness.as_of — staleness is declared, never turned into a 5xx. That date belongs in whatever the agent stores: “the register said no on 1 August 2026” is auditable six months later; “the register said no” is not.

Wiring it up

  1. Send the wording as it will be printed. Not a paraphrase, not a normalised version — the endpoint does the normalising, and the whole point is to test the string that ships.
  2. Send the block, not the sentence. contains_registered is what catches a refused claim buried in three lines of otherwise clean copy.
  3. Branch on verdict, then read claims[].status. A non_authorised verdict can carry authorised entries alongside the refused one; the list is the evidence, the verdict is the gate.
  4. Escalate partial_match and not_in_register, do not clear them. Both mean the register did not answer the question you thought you asked.
  5. Store rejections[].reason and the EFSA reference. They are the reviewer’s justification, already sourced.
  6. Discover, then pay. The 402 → pay → replay cycle is walked with runnable snippets in the Quickstart, and the machine discovery surfaces are described in For agents. Amounts and accepted settlement rails live in the gateway’s /catalogno price appears in this article.

A compliant pack is several dated registers read at once, and the rest of the family applies the same discipline — verbatim, dated, sourced: GET /label/claims/permitted for the drafting direction, GET /label/food/additive for whether an additive is authorised in a given food category, GET /label/cosmetic/ingredient for the annexes of Regulation (EC) No 1223/2009, and GET /label/chem/classify for harmonised CLP classification versioned by ATP.

Register data is the European Commission’s EU Register of nutrition and health claims, reused with attribution under Commission Decision 2011/833/EU. The full parameter and field contract is on the POST /label/claims/check documentation.