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
regimeand you get a400listing the seven regimes - not a plausible default. The same sentence is served back indata.limitson 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
| Parameter | Type | Required | Description |
|---|---|---|---|
start | string | yes | Date of the act that starts the term, strict ISO YYYY-MM-DD (zero-padded) |
duration | number | yes | Length of the term, a positive integer. Bounded: 3650 days, 120 months, 10 years |
regime | string | yes | One of seven closed values, below. Never inferred |
country | string | every regime except calendar_days | ISO 3166-1 alpha-2 code of the holiday calendar to use |
subdivision | string | no | Regional calendar, for example FR-ALSACE-MOSELLE |
unit | string | no | Accepted 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®ime=working_days&country=FR
The seven regimes
regime | Counts | Rollover |
|---|---|---|
calendar_days | Every day, including weekends and holidays | No - and no calendar is consulted at all |
calendar_days_with_rollover | Every day | Yes |
business_days | Monday to Saturday, public holidays excluded | Yes |
working_days | Monday to Friday, public holidays excluded | No |
clear_days (jours francs) | Neither the day of the act nor the day of expiry counts | Yes |
months | Same day-of-month, then the end-of-month rule | Yes |
years | The same rules, in years | Yes |
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_ofis 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
| Field | Type | Description |
|---|---|---|
due_date | string | The answer. Everything else exists so you can verify it |
regime | string | Echo of the requested regime |
duration | number | Echo of the requested length |
unit | string | days, months or years - derived from the regime, never supplied separately |
start_date | string | Echo of the requested starting date |
start_date_effective | string | First 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_counted | number | Days that actually counted. Absent for months and years, where nothing is counted in days |
skipped_days | array | Every day that was skipped, named and dated, in chronological order |
rollover_applied | boolean | Whether the due date was postponed to the next working day (art. 642 CPC) |
rollover_reason | string | The day that caused the postponement. Present only when rollover_applied is true |
steps | array | The calculation in plain sentences, redoable by hand |
calendar_consulted | boolean | false for calendar_days only |
calendar | object | Which calendar was used. Absent for calendar_days: none was consulted |
legal_basis | array | The computation articles actually applied, in a form queryable by /legal/article |
legal_basis_note | string | Why a citation is not served, or why the list is empty. Present when either applies |
limits | array | Three fixed sentences on what this computation is not. Served with every answer |
skipped_days[]
| Field | Type | Description |
|---|---|---|
date | string | The skipped day |
kind | string | weekend or public_holiday |
name | string | Published English label (Sat, Ascension Day) |
name_local | string | Local label, for public holidays only (Ascension) - absent for weekends |
calendar
| Field | Type | Description |
|---|---|---|
country | string | Calendar actually used |
subdivision | string | Present only when a regional calendar was requested |
authority | string | official (published by the State - today France only) or community_dataset (open reference dataset, no official standing) |
window | object | Period the loaded calendar actually covers, both bounds inclusive and derived from the days present, never declared |
as_of | string | Date of the calendar dump |
legal_basis[]
| Field | Type | Description |
|---|---|---|
jurisdiction | string | Jurisdiction of the cited rule |
code | string | Text identifier, queryable by /legal/article |
article | string | Article number |
rule | string | The rule as applied, in one sentence |
available_in_corpus | boolean | Whether /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:
| Request | Skipped | due_date |
|---|---|---|
country=FR | Sat, Sun, Easter Monday | 2026-04-07 |
country=FR&subdivision=FR-ALSACE-MOSELLE | Good Friday, Sat, Sun, Easter Monday | 2026-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.
officialandcommunity_datasetare 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
| Status | code | Case |
|---|---|---|
| 400 | INVALID_INPUT | Missing or unknown regime, malformed start, out-of-range duration, or a unit contradicting the regime |
| 400 | COUNTRY_NOT_COVERED | No holiday calendar for that country - the covered ones are listed |
| 400 | SUBDIVISION_NOT_COVERED | No regional calendar under that code - the covered ones are listed |
| 404 | OUT_OF_COVERAGE_WINDOW | A date falls outside the loaded calendar window |
| 404 | NOT_FOUND | The served store carries no holiday calendar at all |
| 500 | INTERNAL | Internal 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
GET /legal/transposition- the national measures a Member State notified for an EU act.GET /legal/article- the consolidated text of a French article at a date.GET /legal/history- the version timeline of an article.- For agents - discovery surfaces, the live
/catalogand how settlement works.