GET /medication/availability

Returns the market-availability status of a French medication, from the official ANSM shortage reports (data.ANSM): the reported shortages, risks of shortage, tensions, returns to market and discontinuations relayed exactly as published, each with its date, medical domain and the official ansm.sante.fr report URL. The answer is served from a local store built from the open data.ANSM dataset, so a lookup resolves in milliseconds with no network call and no secret at request time.

Use it when an agent needs to check whether a medication is sourceable before acting - order it, prescribe it, or propose an alternative. It extends the “pre-action checks” angle on the prescription and ordering side, a natural pair with /medication/generics (a reference brand is short → which equivalents exist?). Lookup is by identifier or substance only - there is no search by symptom, indication or fuzzy name in v1. See the live /catalog for the authoritative endpoint listing and price.

Shortage reports are a French (data.ANSM) notion. The scope of this endpoint is FR: a US ndc key returns an honest coverage note, never an error, and no US equivalent is promised.

no_known_shortage is not “in stock”

This is the central point of the endpoint. The ANSM only records reported shortages - it is a register of signalements, not a picture of pharmacy stock. So the absence of a report means “no shortage known to the ANSM”, never “available on the shelf”. The synthesis status for a medication with no report is therefore named no_known_shortage (not available), and every FR answer carries the veracity note:

ANSM only records reported shortages; the absence of a report does not guarantee pharmacy stock

An agent must read no_known_shortage as “the ANSM has published nothing about this medication”, not as a positive stock guarantee.

This endpoint returns sourced, dated facts - ANSM statuses, dates and report links exactly as published. It is never a clinical recommendation, a therapeutic alternative or a dosage. That line is the boundary of the service.

x402 golden rule: the agent pays for the answer to its question. A well-formed key with no shortage report is a successful answer too -> a 200 billed with data.status: "no_known_shortage" (or data.found: false for a substance key) - the absence of a report is the information. Only requests the service cannot answer - no key, several keys, a malformed key, an empty substance - leave the 200 range and are not billed.

Parameters

Exactly one of the three keys, as a query parameter. Zero or several keys, a malformed key, or an empty substance/dci is a 400 INVALID_INPUT.

ParameterTypeRequiredDescription
cisstringone of the threeFrench CIS code - exactly 8 digits (BDPM)
substancestringone of the threeINN/DCI substance name, resolved through the shared canonical substance key (substance=acetaminophen finds the paracetamol reports)
dcistringone of the threeSynonym of substance - same join key, not combinable with it (two keys = 400)
ndcstringone of the threeUS product NDC labeler-product (e.g. 0071-0155) - out of FR scope, returns a coverage note
GET /medication/availability?cis=65806466

substance and dci are two names for the same key - pass one, never both. Substance resolution folds through the shared canonical substance key plus the known French labels of the DCI↔INN table, so an English INN reaches the reports of the same molecule.

200 response - UnifiedResponse

{
  "data": { ... },
  "provenance": {
    "source": "ANSM — disponibilité des médicaments (ansm.sante.fr)",
    "fetched_at": "2026-08-01T07:46:37.468309610Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-08-01T00:00:00Z" }
  }
}

provenance depends on the key that resolved the answer:

Key(s)sourcefreshness.kind
cis, substance, dciANSM — disponibilité des médicaments (ansm.sante.fr)snapshot - dated data.ANSM image
ndcmedication-grid availability coverage (data.ANSM scope)live - pure local scope statement, no store consulted

Fields of data

The shape depends on the key - the two FR shapes are never mixed.

FieldTypePresent forDescription
statusstringcisSynthesis status - the status of the most recent report, or no_known_shortage when none exists
signalsobject[]cisThe ANSM reports for that CIS (see below); [] when none
foundboolsubstance/dcifalse with items: [] when no report references the substance - a billed 200
itemsobject[]substance/dciThe reports whose published substances match (same fields as signals[])
notestringevery FR answerThe veracity caveat, quoted above - the absence of a report is not a stock guarantee
coverageobjectcis, ndcFor a cis key, { scope: "FR", note, unlinked_signals } - the bound of the answer (see below); for an ndc key, { scope: "FR", note }, the honest FR-scope statement

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

A signals[] / items[] entry

Both shapes carry the same report fields:

FieldTypeDescription
cisstringThe reported speciality’s CIS - linked from the ANSM name by the pipeline, omitted when not linked, never guessed
match_kindstringHow that cis was linked: exact (the ANSM name equals the BDPM name) or label_prefix (derived - the ANSM name bundles several strengths or a pack annotation, and its brand + strength prefixes exactly one BDPM name). Present exactly when cis is
namestringSpeciality name as published by the ANSM
statusstringReport status - one of rupture / risque_rupture / tension / remise_a_disposition / arret_commercialisation (closed set)
updated_atstringReport update date as published by the ANSM - the only tracking date the source exposes, never a shortage start date (the ANSM table does not publish one)
restock_datestringReturn-to-market date as published: observed for a remise_a_disposition status, forecast otherwise; omitted when none is announced
domainstringMedical domain (e.g. Cardiologie)
source_refstringURL of the official ansm.sante.fr report - traceability

For a cis key, the synthesis status is the status of the most recent report (highest updated_at) - the service never reorders reports by an invented severity. Statuses, dates and links are relayed exactly as published - they are facts, not a recommendation to switch to another medication.

Example - a shortage, resolved by CIS

GET /medication/availability?cis=65806466 (a known shortage), against the 2026-08-01 data.ANSM snapshot:

{
  "data": {
    "status": "rupture",
    "signals": [
      {
        "cis": "65806466",
        "match_kind": "exact",
        "name": "Alprostadil Intsel Chimos 0,5 mg/ml, solution injectable",
        "status": "rupture",
        "updated_at": "2022-11-23",
        "domain": "Cardiologie",
        "source_ref": "https://ansm.sante.fr/disponibilites-des-produits-de-sante/medicaments/alprostadil-intsel-chimos-0-5-mg-ml-solution-injectable-alprostadil"
      }
    ],
    "note": "ANSM only records reported shortages; the absence of a report does not guarantee pharmacy stock",
    "coverage": {
      "scope": "FR",
      "note": "ANSM publishes product labels, not CIS codes; unlinked_signals reports in this snapshot could not be linked to a CIS and are invisible to this key — query ?substance= to check them",
      "unlinked_signals": 60
    }
  },
  "provenance": {
    "source": "ANSM — disponibilité des médicaments (ansm.sante.fr)",
    "fetched_at": "2026-08-01T07:46:37.468309610Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-08-01T00:00:00Z" }
  }
}

The synthesis status is rupture (the most recent report’s status); the report carries no restock_date (no return announced -> the field is omitted). A CIS may carry several reports, in which case status reflects the latest.

A well-formed CIS with no report is a paid answer

GET /medication/availability?cis=60424338 (or an unknown but well-formed CIS such as ?cis=99999999) returns a 200, billed, with:

{
  "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",
      "note": "ANSM publishes product labels, not CIS codes; unlinked_signals reports in this snapshot could not be linked to a CIS and are invisible to this key — query ?substance= to check them",
      "unlinked_signals": 60
    }
  }
}

The agent asked “is a shortage reported for this medication?”, and “none reported” is the answer. Read no_known_shortage as “the ANSM has published no report”, never as “available in stock” - that is exactly why the note travels with every FR answer. Contrast this with the 400s below, which are malformed requests and are not billed.

What a cis answer does not cover

The ANSM publishes product labels, not CIS codes. Linking a report to a CIS is done at ingestion time and is deliberately strict: an exact name match, or a brand + strength prefix that matches exactly one BDPM name (match_kind tells you which). Anything ambiguous is left unlinked rather than guessed - a report about another strength of the same substance is not a shortage of the CIS you asked about.

So every cis answer carries coverage.unlinked_signals: how many reports in the current snapshot carry no CIS at all and are therefore invisible to this key. It is the bound of what no_known_shortage asserts. To rule those out, ask the same question by substance (?substance=), which searches the published substances and returns unlinked reports too.

Resolving by substance

GET /medication/availability?substance=alprostadil (or ?dci=alprostadil) returns a 200, billed, with data.found and data.items[] instead of status + signals:

{
  "data": {
    "found": true,
    "items": [
      {
        "cis": "65806466",
        "match_kind": "exact",
        "name": "Alprostadil Intsel Chimos 0,5 mg/ml, solution injectable",
        "status": "rupture",
        "updated_at": "2022-11-23",
        "domain": "Cardiologie",
        "source_ref": "https://ansm.sante.fr/disponibilites-des-produits-de-sante/medicaments/alprostadil-intsel-chimos-0-5-mg-ml-solution-injectable-alprostadil"
      }
    ],
    "note": "ANSM only records reported shortages; the absence of a report does not guarantee pharmacy stock"
  }
}

A report the pipeline could not link carries no cis and no match_kind - it is still returned here, which is why ?substance= is the way to check what a cis lookup cannot see.

A substance with no matching report returns data.found: false and data.items: [] - a billed 200, no shortage known to the ANSM.

A US NDC is honest coverage, not an error

GET /medication/availability?ndc=0071-0155 returns a 200, billed, with:

"coverage": {
  "scope": "FR",
  "note": "shortage reports come from data.ANSM (French market); NDC keys are out of scope in v1"
}

provenance.source is "medication-grid availability coverage (data.ANSM scope)" and freshness.kind is "live": it is a pure local scope statement, consulting no store (so an ndc key never returns a 503). There is no US shortage-report equivalent in v1 - the endpoint says so honestly rather than guessing.

Freshness

Answers are served from a dated snapshot of the data.ANSM dataset; freshness.as_of carries the date of the extraction that backed the answer. 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) for the cis/substance/dci keys; an ndc key depends on no store and never returns 503.

Errors

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

StatuscodeCase
400INVALID_INPUTZero or several keys; a malformed key (e.g. a cis that is not 8 digits, a package NDC); an empty substance/dci
503DATA_UNAVAILABLEThe data.ANSM dataset has not been ingested yet - there is no last good snapshot to serve (cis/substance/dci only)
404NOT_FOUNDUnknown route
405METHOD_NOT_ALLOWEDWrong HTTP method on a known route (use GET on /medication/availability)
500INTERNALInternal error (detail logged, not exposed)
{ "error": "provide exactly one of: cis, substance, dci, ndc", "code": "INVALID_INPUT" }

Attribution

French shortage data is derived from data.ANSM (disponibilité des médicaments), the open dataset published by the ANSM on ansm.sante.fr (source and date required, carried in every response).

See also

  • GET /medication/generics - the reference brand and equivalent generics of a medication, to source an alternative when one is short.
  • GET /medication/resolve - the official identity card of a medication (status, substances, price) before checking its availability.
  • For agents - discovery surfaces, the live /catalog and how settlement works.