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:
| Endpoint | Input | Reaches |
|---|---|---|
GET /label/claims/permitted | a nutrient | the 269 authorised claims — what you may write |
POST /label/claims/check | a wording | all 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_kind | The submitted wording is… |
|---|---|
exact | exactly a registered claim, once normalised |
contains_registered | longer copy that contains a whole registered claim |
contained_in_registered | a 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”:
| Case | Result |
|---|---|
authorised — every match is authorised | 200, billed |
non_authorised — at least one match is refused, or carries a status outside the nomenclature | 200, billed |
partial_match — a fragment, with the full claims it sits in | 200, billed |
not_in_register — no match, with the nutrient’s authorised claims as fallback | 200, billed |
wording present but empty or blank | 400 MISSING_PARAMETER, not billed |
wording absent, or punctuation with no word in it | 400 INVALID_INPUT, not billed |
nutrient present but empty | 400 INVALID_INPUT, not billed |
| Register not yet ingested | 503 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
- 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.
- Send the block, not the sentence.
contains_registeredis what catches a refused claim buried in three lines of otherwise clean copy. - Branch on
verdict, then readclaims[].status. Anon_authorisedverdict can carry authorised entries alongside the refused one; the list is the evidence, the verdict is the gate. - Escalate
partial_matchandnot_in_register, do not clear them. Both mean the register did not answer the question you thought you asked. - Store
rejections[].reasonand the EFSA reference. They are the reviewer’s justification, already sourced. - 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/catalog— no 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.