GET /legal/article

Returns the consolidated version of a French legal article in force at a given date: article text, LEGI status, validity dates and coverage metadata. The lookup is served from a local store built from the official LEGI dataset, so a covered reference resolves in milliseconds without an account or API key. The corpus currently covers a selected set of French codes and statutes and is expanding; an uncovered reference returns 404, never a paid empty answer.

Use it when an agent needs a grounded answer to questions such as “what was the text of Article 1240 of the Civil Code on this date?” or “is this article repealed?” See the live /catalog for the authoritative endpoint listing and price.

x402 golden rule: the agent pays for the answer to its question. A known article with a version covering the requested date is a successful answer -> 200, including when etat: "abroge" and including after the repeal took effect: “yes, repealed since that date” is the answer, so the endpoint returns the last known version with in_force_at_date: false. Repealed is data, not an error. Requests the service cannot answer - malformed references, invalid dates, unknown articles, or a date no version covers and no repeal explains - leave the 200 range.

Parameters

ParameterTypeRequiredDescription
codestringyesFrench text identifier, for example code-civil; case-insensitive
articlestringyesArticle number within that text, for example 1240
datestringnoUTC date to resolve, strict format YYYY-MM-DD; defaults to today’s date
GET /legal/article?code=code-civil&article=1240&date=2026-01-01

Omit date when the agent wants the version in force today:

GET /legal/article?code=code-civil&article=1240

The code slug is case-insensitive: CODE-CIVIL and code-civil resolve to the same text, and the response echoes the canonical lowercase form.

200 response - UnifiedResponse

{
  "data": { ... },
  "provenance": {
    "source": "legifrance-legi",
    "fetched_at": "2026-06-20T12:00:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-06-01T00:00:00Z" }
  }
}
  • provenance.source: source identifier from the served LEGI store, commonly legifrance-legi.
  • freshness.kind: snapshot; as_of is the LEGI dump date that backed the answer. Freshness is dated per dataset, so a French answer reflects the LEGI snapshot date, independent of the EU corpus.
  • French law data is derived from LEGI, published by DILA under the Licence Ouverte / Etalab open licence.

Fields of data

FieldTypeDescription
codestringEcho of the requested French text identifier
articlestringEcho of the requested article number
datestringEffective resolution date in YYYY-MM-DD form
labelstringHuman label for the resolved article
etatstringLEGI status carried as stored, never reinterpreted by the service
in_force_at_dateboolWhether the served text is the applicable law on date
textstringConsolidated text of the selected version
versionobjectValidity period and source version identifier
coverage_windowobjectPeriod over which this text is actually queryable: from (inclusive), to (exclusive, null when open)
coverageobjectCompleteness marker for the served legal version

Possible etat values follow the LEGI store and may include vigueur, abroge, abroge_diff, vigueur_diff, modifie and perime.

in_force_at_date is the flag to branch on. It saves you from cross-checking etat against version.date_fin and date - a cross-check that is genuinely error-prone, because the French and EU corpora encode a repeal in opposite ways (French law closes the last version’s interval; EU law opens a repeal version that starts at the repeal). The same question gets the same answer and the same flag on both corpora. etat itself is never rewritten.

version

FieldTypeDescription
version_idstringStable identifier of the selected source version
date_debutstringStart date of this version, inclusive, in YYYY-MM-DD
date_finstring | nullEnd date of this version, exclusive; omitted when current

coverage

FieldTypeDescription
completebooltrue when the store served an unambiguous version
reasonstringPresent when complete: false, naming the source dump anomaly

Example - article in force

{
  "data": {
    "code": "code-civil",
    "article": "1240",
    "date": "2026-01-01",
    "label": "Code civil, art. 1240",
    "etat": "vigueur",
    "in_force_at_date": true,
    "text": "Tout fait quelconque de l'homme, qui cause a autrui un dommage, oblige celui par la faute duquel il est arrive a le reparer.",
    "version": {
      "version_id": "v-courant",
      "date_debut": "2016-10-01"
    },
    "coverage": { "complete": true }
  },
  "provenance": {
    "source": "legifrance-legi",
    "fetched_at": "2026-06-20T12:00:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-06-01T00:00:00Z" }
  }
}

Example - repealed article is still a 200

An abrogated article is a successful answer, at any date after the repeal. The status lives in data.etat and the applicability in data.in_force_at_date; neither is converted into an HTTP error. version carries the article’s real validity interval, including the end date - the store’s data is never rewritten to make the answer look tidier.

{
  "data": {
    "code": "code-test",
    "article": "disparu",
    "date": "2026-01-01",
    "label": "Code test, art. disparu",
    "etat": "abroge",
    "in_force_at_date": false,
    "text": "dernier texte connu avant abrogation",
    "version": {
      "version_id": "v-old",
      "date_debut": "1990-01-01",
      "date_fin": "2000-01-01"
    },
    "coverage": { "complete": true }
  },
  "provenance": {
    "source": "legifrance-legi",
    "fetched_at": "2026-06-20T12:00:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-06-01T00:00:00Z" }
  }
}

Coverage honesty

The service answers from a local snapshot of the LEGI corpus. It does not fetch Legifrance at request time, search by keyword, infer missing articles or reinterpret LEGI statuses. etat is carried from the source store as legal metadata; callers should treat it as the authoritative status for the selected version.

coverage.complete: false is reserved for source-store anomalies, such as overlapping versions where the service selected the most recent start date. Unknown articles, and dates that no version covers and no repeal explains, are not partial paid answers: they return 4xx errors.

The service distinguishes a text that is out of scope from an article number that does not exist inside a covered text. If the whole code is not part of the store’s selection, the error is UNKNOWN_TEXT (the text is not covered); if the text is covered but the article number is unknown, it is UNKNOWN_ARTICLE. The covered set of French codes is listed in the live /catalog entry.

Historical depth varies per text

Every answer carries coverage_window: the period this text can actually be read over (from inclusive, to exclusive, null when still open). Depth is not uniform across the corpus — the Code civil goes back to 1804, other texts start at the first consolidation the source dataset publishes.

A date outside that window returns OUT_OF_COVERAGE_WINDOW, which says we do not cover the period — not that the law did not exist:

{
  "error": "text `code-civil` is covered from 1804-03-21 onwards; the store has no data for 1700-01-01. Historical depth varies per text: this is a coverage limit, not a statement about the law",
  "code": "OUT_OF_COVERAGE_WINDOW"
}

Inside the window, a date no version covers stays NO_VERSION_AT_DATE: the text is covered, that article simply had no version then. Both are 4xx and neither is billed. The same window is returned by /legal/history, so a monitoring agent knows how far back to go before spending a call.

Errors

Only requests the service cannot answer leave the 200 range.

StatuscodeCase
400INVALID_REFcode or article is missing, empty or malformed
400INVALID_DATEdate is present but not strictly formatted as YYYY-MM-DD (zero-padded: 2026-07-05, not 2026-7-5)
404UNKNOWN_TEXTThe code is well formed but the whole text is outside the store’s scope
404UNKNOWN_ARTICLEThe text is covered, but no matching article number exists in it
404OUT_OF_COVERAGE_WINDOWThe date falls outside the text’s coverage_window - that period is not covered for this text
404NO_VERSION_AT_DATEWithin the window, the article exists but no version covers the requested date and no repeal explains the gap
500INTERNALInternal error (detail logged, not exposed)
{ "error": "query parameter `code` is required (text identifier, e.g. `code-civil`)", "code": "INVALID_REF" }
{ "error": "invalid `date` `01/01/2026`; expected ISO calendar format YYYY-MM-DD", "code": "INVALID_DATE" }
{ "error": "text `code-de-la-route` is not covered by the store", "code": "UNKNOWN_TEXT" }
{ "error": "no article `9999` found for text `code-civil` in the store", "code": "UNKNOWN_ARTICLE" }
{ "error": "Code civil, art. 1240 has no version in force on 1700-01-01", "code": "NO_VERSION_AT_DATE" }

Attribution

French legislation and regulation data is derived from the LEGI dataset made available by the Direction de l’information legale et administrative (DILA) on Legifrance, under the Licence Ouverte / Etalab open licence.

See also

  • GET /legal/eu-act - consolidated European Union act text at a date.
  • For agents - discovery surfaces, the live /catalog and how settlement works.