# 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. Published 2026-08-11 · HTML version: https://invoket.com/blog/is-this-exact-label-wording-an-authorised-health-claim --- 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`](/docs/api/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`](/docs/api/label-claims-permitted) | a **nutrient** | the 269 authorised claims — what you *may* write | | [`POST /label/claims/check`](/docs/api/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?](/blog/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](https://eur-lex.europa.eu/eli/reg/2024/2041/oj/eng) 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"}`: ```json { "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](https://efsa.onlinelibrary.wiley.com/doi/10.2903/j.efsa.2021.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](https://eur-lex.europa.eu/eli/reg/2024/2105/oj), 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`: ```json { "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](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32012R0432) 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 `200`s — 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 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](/docs/quickstart), and the machine discovery surfaces are described in [For agents](/docs/for-agents). Amounts and accepted settlement rails live in the gateway's [`/catalog`](https://api.invoket.com/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`](/docs/api/label-claims-permitted) for the drafting direction, [`GET /label/food/additive`](/docs/api/label-food-additive) for whether an additive is authorised in a given food category, [`GET /label/cosmetic/ingredient`](/docs/api/label-cosmetic-ingredient) for the annexes of Regulation (EC) No 1223/2009, and [`GET /label/chem/classify`](/docs/api/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](/docs/api/label-claims-check).