# Check a medication for shortages: the French ANSM register > The ANSM register lists declared shortages, not pharmacy stock. That is why /medication/availability answers no_known_shortage and never "available". Published 2026-08-10 · Updated 2026-08-16 · HTML version: https://invoket.com/blog/check-a-medication-for-reported-shortages-before-ordering --- An agent that is about to order a medication, promise a delivery date or offer a substitute needs to know whether an authority has published a supply problem for it. [`GET /medication/availability`](/docs/api/medication-availability) answers that from the official **ANSM** shortage reports — rupture, risk of shortage, tension, return to market, discontinuation — relayed exactly as published, each with its date, medical domain and official report URL. What it will never return is a status called `available`. The synthesis status for a medication with no report is named **`no_known_shortage`**, and that naming choice is the whole subject of this article: it is the difference between a fact and a guarantee an agent must not infer. ## The ANSM register is a register of declarations The French dataset is built from what pharmaceutical companies **declared**. Marketing authorisation holders and operators of *médicaments d'intérêt thérapeutique majeur* (MITM) must report a shortage or a risk of shortage to the ANSM, under [article R. 5124-49-1 of the code de la santé publique](https://ansm.sante.fr/vos-demarches/industriel/declarer-une-rupture-de-stock-mitm), through the Trustmed filing platform, and the agency insists they do so *as early as possible*. The ANSM says what that makes the published list, on its own page: > These tables do not list all MITM but the medicines that were subject to a > declaration of shortage or risk of shortage during the year. > — [ANSM, *Médicaments ayant fait l'objet d'un signalement de rupture*](https://ansm.sante.fr/page/medicaments-ayant-fait-lobjet-dun-signalement-de-rupture-ou-de-risque-de-rupture-de-stock) So the register answers exactly one question: **has a supply problem been declared to the French agency for this product?** It is not an inventory. No public dataset in France carries what is on a pharmacy shelf this morning, and an API that implied otherwise would be inventing the most operationally dangerous field in the response. ## `no_known_shortage`, never `available` The endpoint encodes that boundary in the status name itself. A well-formed CIS with no report comes back as a **billed 200**: ```json { "data": { "status": "no_known_shortage", "signals": [], "note": "ANSM only records reported shortages; the absence of a report does not guarantee pharmacy stock", "coverage": { "scope": "FR", "unlinked_signals": 61 } } } ``` Three things are doing work here. - **The status is a statement about the register**, not about the product. Read `no_known_shortage` as "the ANSM has published nothing about this medication". - **The `note` travels with every French answer**, not just the empty ones. It is a field rather than a footnote because agents read fields, and the caveat has to survive being passed through a summariser. - **The empty `signals: []` is the answer**, not a miss. The agent asked whether a shortage was reported; "none reported" is information, and it is billed as such. The rule to wire in is one line: **`no_known_shortage` is a green light to keep looking, not a green light to promise a delivery.** ## Five statuses, relayed exactly as published When reports do exist, they come back verbatim. `status` is a closed set of the five categories the ANSM publishes: | Status | What the ANSM declared | |---------------------------|---------------------------------------------------| | `rupture` | Shortage — the product cannot be supplied | | `risque_rupture` | A shortage is anticipated | | `tension` | Supply is strained | | `remise_a_disposition` | The product is back on the market | | `arret_commercialisation` | Marketing has been discontinued | A real report, resolved by CIS: ```json { "status": "tension", "signals": [ { "cis": "65979151", "match_kind": "exact", "name": "Lantus Solostar 100 unités/ ml, solution injectable en stylo prérempli", "status": "tension", "updated_at": "2026-04-02", "domain": "Endocrinologie", "source_ref": "https://ansm.sante.fr/disponibilites-des-produits-de-sante/medicaments/lantus-solostar-100-unites-ml-solution-injectable-en-stylo-prerempli-insuline-glargine" } ] } ``` Two date fields deserve care, because both are easy to over-read: - **`updated_at` is the report's update date** — the only tracking date the source publishes. It is **not** the date the shortage started; the ANSM table does not carry one, so the service does not invent one. - **`restock_date` is a return date as published**: *observed* when the status is `remise_a_disposition`, *forecast* otherwise, and **omitted** when nothing has been announced. A resolved case carries both, as with Quinimax 500 mg — `remise_a_disposition`, `updated_at` and `restock_date` on `2026-07-16`. When a CIS carries several reports, the synthesis `status` is the status of the **most recent** one. The service never reorders reports by an invented severity scale — that would be the service forming an opinion. ## The bound a CIS lookup cannot see Here is the second honesty problem, and the reason every `cis` answer carries a `coverage` block. **The ANSM publishes product labels, not CIS codes.** Linking a report to a BDPM code happens at ingestion and is deliberately strict: an exact name match, or a `brand + strength` prefix matching exactly one BDPM name — `match_kind` tells you which. Anything ambiguous is left unlinked rather than guessed, because a report about another strength of the same substance is *not* a shortage of the product you asked about. Atropine eye drops show what that costs. Asking by substance returns three reports, and **none of them carries a `cis`**: ```json { "found": true, "items": [ { "name": "Atropine 0,3%, collyre", "status": "arret_commercialisation", "updated_at": "2026-01-06", "domain": "Ophtalmologie" }, { "name": "Atropine 1%, collyre", "status": "tension", "updated_at": "2024-10-16", "domain": "Ophtalmologie" }, { "name": "Atropine 0,5%, collyre", "status": "tension", "updated_at": "2024-07-18", "domain": "Ophtalmologie" } ] } ``` Phenobarbital is the mixed case that makes the mechanism concrete: `Gardénal 50 mg, comprimé` links to CIS `65391080` with `match_kind: "exact"`, while `Alepsal, comprimé` — reported on the same day, same domain — links to nothing and comes back with no `cis` at all. That is what `coverage.unlinked_signals` counts: the reports in the current snapshot that carry no CIS and are therefore **invisible to a `cis` query**. It is the published bound of what `no_known_shortage` asserts. To rule them out, ask the same question by substance: ```http GET /medication/availability?substance=atropine ``` The substance key searches the published substance names and returns unlinked reports too, with `found` / `items[]` instead of `status` / `signals[]`. `dci` is a synonym of `substance` — pass one, never both. Substance resolution folds through the same canonical key the rest of the family uses, so an English INN reaches the French reports of the same molecule. ## Why this is a French dataset, and why that is not a gap in ambition EU-level shortage reporting has been centralised since the EMA's **European Shortages Monitoring Platform (ESMP)**, live for routine reporting by marketing authorisation holders on [28 November 2024 and in full scope on 29 January 2025](https://www.ema.europa.eu/en/human-regulatory-overview/post-authorisation/medicine-shortages-availability-issues/european-shortages-monitoring-platform-esmp). It is genuinely machine-to-machine — for **submission**. Reading it requires an EMA account and an ESMP role, and access is tiered by a data-access policy. There is no public dataset behind it. Open, per-product, dated shortage data that anyone can serve is therefore a national-register story today, and France publishes one. Hence the scope: a US `ndc` key returns an **honest coverage note**, never an error and never a guess: ```json { "coverage": { "scope": "FR", "note": "shortage reports come from data.ANSM (French market); NDC keys are out of scope in v1" } } ``` That branch consults no store, so `provenance.freshness.kind` is `live` and an `ndc` key can never return a `503`. There is no US equivalent in v1, and the endpoint says so rather than pretending. ## Facts and dates, never a clinical opinion The endpoint relays ANSM statuses, dates and report links. It does not recommend a therapeutic alternative, a dosage or a course of action — the same line the whole medication family holds. `source_ref` on every report points at the official ansm.sante.fr page so a human can verify the claim the agent acted on. Answers are served from a **dated snapshot** of the data.ANSM dataset, with no network call and no secret at request time: ```json "provenance": { "source": "ANSM — disponibilité des médicaments (ansm.sante.fr)", "freshness": { "kind": "snapshot", "as_of": "..." } } ``` `as_of` names the extraction the answer was built from. A missed refresh keeps serving the last good snapshot, honestly dated — **staleness is never turned into a `5xx`**. A dataset never ingested at all is a `503`, because there is nothing to serve, not because the data is old. ## What you pay for The x402 golden rule applies literally: the agent pays for the answer to its question. 1. **Discover** the endpoint in the live catalog, call it, receive the `402`. 2. **Pay** — sign the chosen rail and replay the request. 3. **Read `status` and `coverage` together**, never `status` alone. 4. **Branch** — proceed, look for an equivalent, or escalate. A well-formed CIS with no report is a **billed 200** (`no_known_shortage`), and so is a substance with no match (`found: false`, `items: []`). Only requests the service cannot answer leave the 200 range, and none of them are billed: ```json { "error": "provide exactly one of: cis, substance, dci, ndc", "code": "INVALID_INPUT" } ``` Zero or several keys, a CIS that is not eight digits, a package-level NDC, an empty `substance` — all `400`, none billed. [Quickstart](/docs/quickstart) walks the full discover → `402` → pay → replay cycle; price and accepted rails are served live by the [catalog](https://api.invoket.com/catalog), never pinned in an article. ## Chain it A shortage answer is usually the middle of a workflow, not the end. [`GET /medication/resolve`](/docs/api/medication-resolve) gives the identity card behind the code you are about to check — marketing status, canonical substances, presentations. When a reference brand is short, [`GET /medication/generics`](/docs/api/medication-generics) returns its BDPM generic group so the agent can check the equivalents for reports too, and [`POST /medication/interactions`](/docs/api/medication-interactions) checks the alternative against the rest of the list before it is proposed. For identity, generics, reported shortages and interactions on one medication in a single settlement, use the composite [`GET /medication/report`](/docs/api/medication-report). For the full field reference, the `coverage` semantics and the error codes, see the [`GET /medication/availability` documentation](/docs/api/medication-availability); for how agents discover and call Invoket endpoints, see [For agents](/docs/for-agents).