GET /label/claims/permitted

Lists the authorised health claims for a nutrient or substance against the EU Register of nutrition and health claims (Regulation (EC) 1924/2006). For a nutrient, the answer is the set of claims an agent may legally write — the exact legal wording of each authorised claim, with its conditions of use as written and the referenced EFSA opinion. The register is served from a local store, so a lookup resolves in milliseconds with no network call and no secret at request time.

This is the catalogue counterpart of /label/claims/check: check starts from a wording (“is this text legal?”), permitted starts from a nutrient (“what may I write?”). Both read the same dated register. Use permitted when an agent needs to build a compliant label — the natural sequel to /label/chem/classify and /label/chem/svhc. The register is binding to the character: permitted serves the legal wording as published, not a paraphrase — where an LLM invents a plausible-sounding but non-conforming claim, this endpoint answers from the register as published, dated and sourced. See the live /catalog for the authoritative endpoint listing and price.

This endpoint relays the register content exactly as published — the legal wording and the conditions of use as written. It is never legal advice, nor a label-copy recommendation — it lists the authorised claims of a nutrient, it does not decide what your specific label should say. That line is the boundary of the service.

x402 golden rule: the agent pays for the answer to its question. “Which claims are authorised for this nutrient?” is a well-formed question, and an empty list is the information200 billed even when a nutrient has no authorised claim, or is not in the register at all — never a 404. Only requests the service cannot answer — a missing or empty nutrient — leave the 200 range and are not billed.

Request

GET with a required query parameter — the lookup key is short, so it is passed in the query string (unlike /label/claims/check, which takes a long wording in a POST body).

GET /label/claims/permitted?nutrient=vitamin%20c
ParameterTypeRequiredDescription
nutrientstringyesThe nutrient / substance whose authorised claims you want. Absent, empty, or empty after trim400 MISSING_PARAMETER, not billed

The key is normalised (case, whitespace) before lookup; data.nutrient returns the canonical form actually queried. There is deliberately no fuzzy search (a scoping decision): the nutrient must exist in the register under its normalised form, otherwise the verdict is unknown_nutrient.

200 response — UnifiedResponse

{
  "data": { "nutrient": "vitamin c", "verdict": "found", "authorised": [ ... ], "non_authorised_count": 0 },
  "provenance": {
    "source": "EU Register on nutrition and health claims",
    "fetched_at": "2026-07-24T09:00:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-23T00:00:00Z" }
  }
}

freshness.as_of is dated by the extraction of the register served (meta.json), not by the ingestion date — the dated register is the point of the answer. Both claims endpoints (check and permitted) read the same store, so they share the same as_of.

Fields of data

FieldTypeDescription
nutrientstringThe normalised (canonical) key actually queried
verdictstringfound | none_authorised | unknown_nutrientall three are billed 200s
authorisedobject[]The authorised claims of the nutrient as published (see below); empty on none_authorised and unknown_nutrient
non_authorised_countnumberThe count of non-authorised claims of the nutrient — explains an empty authorised list; 0 on unknown_nutrient
notestringunknown_nutrient only — the dated contractual limit note (see below)

A field the source does not carry is omitted from the JSON, never served null.

The three verdicts

All three are 200 billed — the golden rule: an empty list of authorised claims is the answer, never a 404.

  • found — the nutrient is in the register with at least one authorised claim (authorised[] is non-empty).
  • none_authorised — the nutrient is in the register but has no authorised claim (all rejected): authorised: [], explained by non_authorised_count > 0. The empty list is honestly accounted for, not a silent omission — the nutrient exists, its claims were all refused.
  • unknown_nutrient — the nutrient is absent from the register: authorised: [], non_authorised_count: 0, plus a note. This is not “no claim is possible”, never a 404.

non_authorised_count is the honest distinction between the two empty-list cases: a positive count means none_authorised (a known nutrient, everything rejected); 0 with unknown_nutrient means the nutrient is simply not in the register.

An authorised[] entry — the register as published

Each entry is the register content relayed as published, never reformulated — the same ClaimView shape as /label/claims/check, carrying only authorised claims here:

FieldTypeDescription
codestringRegister code (e.g. POL-HC-00157)
typestringBase article (e.g. Art. 13.1); omitted if not published
statusstringVerbatim register status — authorised (only authorised claims are listed here)
nutrientstringThe nutrient / substance the claim is about
wordingstringThe exact LEGAL wording of the register — what the agent may copy, character for character
conditions_of_usestringConditions of use as written; omitted if none
efsaobject{ question, url } of the referenced EFSA opinion; omitted if none
legislationstringThe implementing act; omitted if none

The wording field is the register’s legal wording. An agent building a compliant label copies this, not a paraphrase — that is the whole value of the endpoint.

Example — a nutrient with authorised claims (billed)

GET /label/claims/permitted?nutrient=vitamin%20c — the nutrient is in the register with authorised claims, so the verdict is found:

{
  "data": {
    "nutrient": "vitamin c",
    "verdict": "found",
    "authorised": [
      {
        "code": "POL-HC-00157",
        "type": "Art. 13.1",
        "status": "authorised",
        "nutrient": "Vitamin C",
        "wording": "Vitamin C contributes to normal collagen formation for the normal function of blood vessels",
        "conditions_of_use": "The claim may be used only for food which is at least a source of vitamin C as referred to in the claim SOURCE OF [NAME OF VITAMIN/S] and/or [NAME OF MINERAL/S] as listed in the Annex to Regulation (EC) No 1924/2006.",
        "efsa": {
          "question": "Q-2008-1226",
          "url": "https://www.efsa.europa.eu/en/efsajournal/pub/Q-2008-1226"
        },
        "legislation": "Commission Regulation (EU) No 432/2012"
      }
    ],
    "non_authorised_count": 0
  },
  "provenance": {
    "source": "EU Register on nutrition and health claims",
    "fetched_at": "2026-07-24T09:00:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-23T00:00:00Z" }
  }
}

The wording is the legal text as published; the agent copies it verbatim. non_authorised_count is 0 here — every listed claim is authorised.

Example — a known nutrient with no authorised claim (billed)

A nutrient the register carries but whose claims were all rejected returns a 200, billed, with an empty authorised list explained by non_authorised_count:

{
  "data": {
    "nutrient": "isomaltulose",
    "verdict": "none_authorised",
    "authorised": [],
    "non_authorised_count": 1
  },
  "provenance": {
    "source": "EU Register on nutrition and health claims",
    "fetched_at": "2026-07-24T09:00:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-23T00:00:00Z" }
  }
}

The empty list is not a silence: non_authorised_count: 1 says the nutrient is in the register and its claim was refused — an honest none_authorised, not an unknown_nutrient. To read the full rejection reason and EFSA opinion for that claim, check its wording with /label/claims/check (the isomaltulose sentinel).

Example — a nutrient absent from the register (billed)

A nutrient the register does not carry returns a 200, billed, with an empty list and a dated limit note in plain sight, never a 404:

{
  "data": {
    "nutrient": "ginkgo biloba",
    "verdict": "unknown_nutrient",
    "authorised": [],
    "non_authorised_count": 0,
    "note": "Absence from the register is not an authorisation and not a prohibition. In particular, botanical claims 'on hold' under Article 13(1) are not in the register and may still be usable during the transitional regime."
  },
  "provenance": {
    "source": "EU Register on nutrition and health claims",
    "fetched_at": "2026-07-24T09:00:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-23T00:00:00Z" }
  }
}

The honest limit: absent from the register ≠ prohibited. non_authorised_count is 0 (not a single claim, authorised or rejected, is on file), and the note is careful never to read “not in the register” as “forbidden” — the botanicals ‘on hold’ regime (Article 13(1)) is the canonical case of a usable claim that is not in the register.

Complementary to the claim check

The two claims endpoints read the same dated register from opposite directions — use them together to build and then verify a label:

EndpointInputAnswer
GET /label/claims/permitted (this page)a nutrientthe authorised claims you may write (legal wording)
POST /label/claims/checka proposed wordingwhether that text is authorised / non-authorised / absent

An agent typically lists the authorised claims for its nutrient here, copies the legal wording, then checks its final label text with /label/claims/check before shipping.

Freshness

Answers are served from a snapshot of the register, dated by the extraction served (freshness.as_of), not by the ingestion date. The register is refreshed off-band; if a refresh is missed, the service keeps serving the last good snapshot — honestly dated by as_of — and never turns staleness into a 5xx. A dataset not yet ingested at all is a 503 DATA_UNAVAILABLE (there is no last good snapshot to serve).

Errors

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

StatuscodeCase
400MISSING_PARAMETERnutrient absent, empty, or empty after trim
503DATA_UNAVAILABLEThe register dataset has not been ingested yet — there is no last good snapshot to serve
404NOT_FOUNDUnknown route
500INTERNALInternal error (detail logged, not exposed)
{ "error": "nutrient is required", "code": "MISSING_PARAMETER" }

A 503 for a dataset that is not yet ingested is distinct from staleness: a missed refresh serves the last snapshot, flagged by freshness.as_of, and is never a 5xx.

Attribution

Register data is the European Commission — EU Register of nutrition and health claims made on foods, reused with attribution under Commission Decision 2011/833/EU. EFSA opinions are referenced by their question number and URL.

See also