GET /legal/deadline

Dates a legal time limit: given a starting date, a length and a computation regime, it returns the due date, together with everything needed to check it without taking our word for it - every weekend and public holiday that was skipped, named and dated, the end-of-month and next-working-day rules that were applied, and the calculation written out step by step.

The answer is pure computation over a local holiday index loaded at boot, so a covered request resolves in milliseconds with no network call and no secret at request time. See the live /catalog for the authoritative endpoint listing and price.

The regime is required and is never inferred from the legal matter. This endpoint dates a term; it does not advise which term applies, nor which regime governs it. Ask for a deadline without a regime and you get a 400 listing the seven regimes - not a plausible default. The same sentence is served back in data.limits on every successful answer, because a date computed under the wrong regime looks exactly like a date computed under the right one.

x402 golden rule: the agent pays for the answer to its question. A well-formed request under a covered calendar returns its due date -> 200. Requests the service cannot answer - a missing or unknown regime, an uncovered country, a date outside the loaded calendar window - leave the 200 range and are not billed: a deadline is never computed on a guessed calendar.

Parameters

ParameterTypeRequiredDescription
startstringyesDate of the act that starts the term, strict ISO YYYY-MM-DD (zero-padded)
durationnumberyesLength of the term, a positive integer. Bounded: 3650 days, 120 months, 10 years
regimestringyesOne of seven closed values, below. Never inferred
countrystringevery regime except calendar_daysISO 3166-1 alpha-2 code of the holiday calendar to use
subdivisionstringnoRegional calendar, for example FR-ALSACE-MOSELLE
unitstringnoAccepted as a cross-check only: the unit follows from the regime and may be omitted. A contradiction is a 400
GET /legal/deadline?start=2026-05-06&duration=5&regime=working_days&country=FR

The seven regimes

regimeCountsRollover
calendar_daysEvery day, including weekends and holidaysNo - and no calendar is consulted at all
calendar_days_with_rolloverEvery dayYes
business_daysMonday to Saturday, public holidays excludedYes
working_daysMonday to Friday, public holidays excludedNo
clear_days (jours francs)Neither the day of the act nor the day of expiry countsYes
monthsSame day-of-month, then the end-of-month ruleYes
yearsThe same rules, in yearsYes

Every regime except calendar_days consults a holiday calendar and therefore requires country. unit is derived from the regime (days, months or years) and echoed in the response - a term in months with a duration in days does not exist, so passing unit=days with regime=months is refused rather than silently reinterpreted.

Covered calendars

FR comes from the official calendar published by the French State (api.gouv.fr / Etalab). BE, DE, ES, IE, IT, LU, NL, PL and PT come from an open community reference dataset (Nager.Date), which has no official standing. Which one backed an answer is carried in data.calendar.authority on every response - a community dataset never silently becomes published law.

Any other country code is refused with 400 COUNTRY_NOT_COVERED, listing the covered ones.

Optional regional calendars: FR-ALSACE-MOSELLE, FR-BL, FR-GF, FR-GP, FR-MF, FR-MQ, FR-NC, FR-PF, FR-PM, FR-RE, FR-WF, FR-YT.

200 response - UnifiedResponse

{
  "data": { ... },
  "provenance": {
    "source": "official-holiday-calendars",
    "fetched_at": "2026-07-29T16:04:23Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-29T00:00:00Z" }
  }
}
  • provenance.source: official-holiday-calendars.
  • freshness.kind: snapshot; as_of is the date of the holiday-calendar dump that backed the answer. It has its own annual refresh cycle, independent of the LEGI and EUR-Lex dumps behind /legal/article.

Fields of data

FieldTypeDescription
due_datestringThe answer. Everything else exists so you can verify it
regimestringEcho of the requested regime
durationnumberEcho of the requested length
unitstringdays, months or years - derived from the regime, never supplied separately
start_datestringEcho of the requested starting date
start_date_effectivestringFirst day actually counted, after the start-day rule (art. 641 CPC: the day of the act does not count). Equal to start for months and years, whose day-of-month is the anchor
days_countednumberDays that actually counted. Absent for months and years, where nothing is counted in days
skipped_daysarrayEvery day that was skipped, named and dated, in chronological order
rollover_appliedbooleanWhether the due date was postponed to the next working day (art. 642 CPC)
rollover_reasonstringThe day that caused the postponement. Present only when rollover_applied is true
stepsarrayThe calculation in plain sentences, redoable by hand
calendar_consultedbooleanfalse for calendar_days only
calendarobjectWhich calendar was used. Absent for calendar_days: none was consulted
legal_basisarrayThe computation articles actually applied, in a form queryable by /legal/article
legal_basis_notestringWhy a citation is not served, or why the list is empty. Present when either applies
limitsarrayThree fixed sentences on what this computation is not. Served with every answer

skipped_days[]

FieldTypeDescription
datestringThe skipped day
kindstringweekend or public_holiday
namestringPublished English label (Sat, Ascension Day)
name_localstringLocal label, for public holidays only (Ascension) - absent for weekends

calendar

FieldTypeDescription
countrystringCalendar actually used
subdivisionstringPresent only when a regional calendar was requested
authoritystringofficial (published by the State - today France only) or community_dataset (open reference dataset, no official standing)
windowobjectPeriod the loaded calendar actually covers, both bounds inclusive and derived from the days present, never declared
as_ofstringDate of the calendar dump
FieldTypeDescription
jurisdictionstringJurisdiction of the cited rule
codestringText identifier, queryable by /legal/article
articlestringArticle number
rulestringThe rule as applied, in one sentence
available_in_corpusbooleanWhether /legal/article can serve that article’s text today. The citation is exact either way

Example - working days across a public holiday

Five working days from 6 May 2026 in France. Four days were skipped, each one named: the agent can see why the answer is the 15th and not the 11th.

{
  "data": {
    "due_date": "2026-05-15",
    "regime": "working_days",
    "duration": 5,
    "unit": "days",
    "start_date": "2026-05-06",
    "start_date_effective": "2026-05-07",
    "days_counted": 5,
    "skipped_days": [
      { "date": "2026-05-08", "kind": "public_holiday", "name": "Victory in Europe Day", "name_local": "8 mai" },
      { "date": "2026-05-09", "kind": "weekend", "name": "Sat" },
      { "date": "2026-05-10", "kind": "weekend", "name": "Sun" },
      { "date": "2026-05-14", "kind": "public_holiday", "name": "Ascension Day", "name_local": "Ascension" }
    ],
    "rollover_applied": false,
    "steps": [
      "day of the act 2026-05-06 is not counted (art. 641 CPC): counting starts on the next day",
      "5 working days (Monday to Friday, public holidays excluded) counted: 2026-05-07 to 2026-05-15, 4 day(s) skipped",
      "regime `working_days` applies no rollover: due date stands at 2026-05-15"
    ],
    "calendar_consulted": true,
    "calendar": {
      "country": "FR",
      "authority": "official",
      "window": { "from": "2015-01-01", "to": "2029-12-26" },
      "as_of": "2026-07-29"
    },
    "legal_basis": [
      {
        "jurisdiction": "FR",
        "code": "code-de-procedure-civile",
        "article": "641",
        "rule": "the day of the act is not counted; a term expressed in months or years expires on the day bearing the same day-of-month",
        "available_in_corpus": false
      },
      {
        "jurisdiction": "FR",
        "code": "code-de-procedure-civile",
        "article": "642",
        "rule": "a term expiring on a Saturday, a Sunday, a public holiday or a non-working day is extended to the next working day",
        "available_in_corpus": false
      }
    ],
    "legal_basis_note": "text `code-de-procedure-civile` is not part of the ingested corpus today: the citation is exact, but `/legal/article` cannot serve its text yet",
    "limits": [
      "The computation regime is chosen by the caller and never inferred from the legal matter: this endpoint dates a term, it does not advise which term or which regime applies.",
      "Computation is in civil days, without time of day: hourly time limits, court closing hours, judicial vacations and non-working days set by contract or collective agreement are out of scope.",
      "Holiday calendars carry their own authority: `official` is the calendar published by the State, `community_dataset` is an open dataset used as a reference and has no official standing."
    ]
  },
  "provenance": {
    "source": "official-holiday-calendars",
    "fetched_at": "2026-07-29T16:04:23Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-29T00:00:00Z" }
  }
}

Example - months, the end-of-month rule and a rollover

One month from 31 January 2026. Day 31 does not exist in February, so the end-of-month rule lands on the 28th - a Saturday - and article 642 pushes the term to the following Monday. Two rules, both named in steps.

{
  "data": {
    "due_date": "2026-03-02",
    "regime": "months",
    "duration": 1,
    "unit": "months",
    "start_date": "2026-01-31",
    "start_date_effective": "2026-01-31",
    "skipped_days": [
      { "date": "2026-02-28", "kind": "weekend", "name": "Sat" },
      { "date": "2026-03-01", "kind": "weekend", "name": "Sun" }
    ],
    "rollover_applied": true,
    "rollover_reason": "due date 2026-02-28 falls on a Sat",
    "steps": [
      "term of 1 months: the deadline expires on the day bearing the same day-of-month as 2026-01-31 (art. 641 CPC)",
      "day 31 does not exist in the target month: end-of-month rule applies, due date is 2026-02-28",
      "2026-02-28 is not a working day (Sat): deadline extended (art. 642 CPC)",
      "2026-03-01 is not a working day (Sun): deadline extended (art. 642 CPC)",
      "rolled over to the next working day: 2026-03-02"
    ],
    "calendar_consulted": true,
    "calendar": {
      "country": "FR",
      "authority": "official",
      "window": { "from": "2015-01-01", "to": "2029-12-26" },
      "as_of": "2026-07-29"
    }
  }
}

days_counted is absent here: a term in months counts no days, and the service does not manufacture a number to fill the field.

Example - calendar_days, where nothing is skipped

The one regime that consults no calendar at all. country is not required, calendar is absent, skipped_days is empty and legal_basis is empty with a note saying why - an empty list without a reason would read as “no rule exists”.

{
  "data": {
    "due_date": "2026-05-11",
    "regime": "calendar_days",
    "duration": 5,
    "unit": "days",
    "start_date": "2026-05-06",
    "start_date_effective": "2026-05-07",
    "days_counted": 5,
    "skipped_days": [],
    "rollover_applied": false,
    "steps": [
      "day of the act 2026-05-06 is not counted (art. 641 CPC): counting starts on 2026-05-07",
      "5 calendar days counted: 2026-05-07 to 2026-05-11",
      "regime `calendar_days` applies no rollover: due date stands at 2026-05-11"
    ],
    "calendar_consulted": false,
    "legal_basis": [],
    "legal_basis_note": "no country was given, so no national computation rules are cited; regime `calendar_days` consults no calendar"
  }
}

Example - clear days on a community calendar

Ten jours francs from 6 May 2026 on the German calendar. Two things are said out loud: the calendar is a community_dataset, and articles 641 and 642 of the French Code de procédure civile do not govern German procedure - so legal_basis is empty and the note says the chosen regime was applied to the DE calendar as such.

{
  "data": {
    "due_date": "2026-05-18",
    "regime": "clear_days",
    "duration": 10,
    "unit": "days",
    "start_date": "2026-05-06",
    "start_date_effective": "2026-05-07",
    "days_counted": 10,
    "skipped_days": [
      { "date": "2026-05-17", "kind": "weekend", "name": "Sun" }
    ],
    "rollover_applied": true,
    "rollover_reason": "due date 2026-05-17 falls on a Sun",
    "steps": [
      "clear days: the day of the act 2026-05-06 does not count, counting starts on 2026-05-07",
      "10 clear days counted: 2026-05-07 to 2026-05-16",
      "the day of expiry does not count either: due date moves to 2026-05-17",
      "2026-05-17 is not a working day (Sun): deadline extended (art. 642 CPC)",
      "rolled over to the next working day: 2026-05-18"
    ],
    "calendar_consulted": true,
    "calendar": {
      "country": "DE",
      "authority": "community_dataset",
      "window": { "from": "2015-01-01", "to": "2029-12-26" },
      "as_of": "2026-07-29"
    },
    "legal_basis": [],
    "legal_basis_note": "no computation rules are on record for country `DE`: articles 641 and 642 of the French Code de procédure civile govern French procedure only. The regime you chose was applied to the `DE` holiday calendar as such"
  }
}

Example - a regional calendar changes the date

Three working days from 1 April 2026 in France. Good Friday is a public holiday in Alsace-Moselle and nowhere else in France, and that single day moves the answer:

RequestSkippeddue_date
country=FRSat, Sun, Easter Monday2026-04-07
country=FR&subdivision=FR-ALSACE-MOSELLEGood Friday, Sat, Sun, Easter Monday2026-04-08

data.calendar.subdivision is echoed when a regional calendar was used, so the answer always says which of the two it is.

What this endpoint will not do

The three sentences below travel in data.limits with every answer. They are the contract, not small print.

  • It does not choose the term or the regime for you. The regime is the caller’s decision, and the endpoint dates a term rather than advising which one applies.
  • It counts civil days, not hours. Hourly time limits, court closing hours, judicial vacations and non-working days set by contract or collective agreement are out of scope.
  • It does not upgrade a community dataset into published law. official and community_dataset are carried on every answer precisely so the difference cannot be lost in an integration.

It also does not search for the deadline applicable to a situation, interpret a contract, or reason about time zones and filing hours.

Coverage window

data.calendar.window states the period the loaded calendar actually covers, both bounds inclusive, derived from the days present rather than declared. A start or a due date outside it returns 404 OUT_OF_COVERAGE_WINDOW and is not billed: days whose holiday status is unknown are never counted as ordinary days.

Errors

StatuscodeCase
400INVALID_INPUTMissing or unknown regime, malformed start, out-of-range duration, or a unit contradicting the regime
400COUNTRY_NOT_COVEREDNo holiday calendar for that country - the covered ones are listed
400SUBDIVISION_NOT_COVEREDNo regional calendar under that code - the covered ones are listed
404OUT_OF_COVERAGE_WINDOWA date falls outside the loaded calendar window
404NOT_FOUNDThe served store carries no holiday calendar at all
500INTERNALInternal error (detail logged, not exposed)
{ "code": "INVALID_INPUT", "error": "query parameter `regime` is required; choose one of calendar_days, calendar_days_with_rollover, business_days, working_days, clear_days, months, years — the regime is never inferred from the legal matter" }
{ "code": "COUNTRY_NOT_COVERED", "error": "no holiday calendar for country `US`; covered countries: BE, DE, ES, FR, IE, IT, LU, NL, PL, PT" }
{ "code": "OUT_OF_COVERAGE_WINDOW", "error": "date 2032-05-06 is outside the loaded holiday calendar for `FR` (2015-01-01 to 2029-12-26 inclusive)" }
{ "code": "INVALID_INPUT", "error": "`unit` `days` contradicts regime `months`, which counts in months; the unit follows from the regime and may be omitted" }

Every refusal names what is covered, so a second call can succeed.

Attribution

The French public-holiday calendar is derived from the open dataset published by the French State (api.gouv.fr / Etalab) under the Licence Ouverte / Etalab. The nine other national calendars come from the Nager.Date open reference dataset, which has no official standing. Articles 641 and 642 of the Code de procédure civile are cited from the LEGI dataset made available by the Direction de l’information légale et administrative (DILA) on Légifrance.

See also