What date does this legal deadline fall on?

Agents should not guess due dates. One call returns the deadline under an explicitly chosen computation regime, with every skipped weekend and holiday named.

By Matthias Begot ·

An agent that files a response, serves a notice or schedules a termination has to commit to a date. Adding days to a date looks like the easiest thing in the request — it is the part most likely to be silently wrong, because the answer depends on a counting rule the agent was never told, a national holiday calendar it does not carry, and a rollover rule that may or may not apply. One paid call — GET /legal/deadline — returns the due date under a computation regime you choose explicitly, together with every weekend and public holiday it skipped, named and dated, and the calculation written out step by step.

Three independent things can be wrong about a due date

“Five days from 6 May” is not a computation. It is a question with at least three unstated parameters:

  1. What counts as a day. Calendar days, working days (Monday to Friday), business days (Monday to Saturday), or jours francs — clear days, where neither the day of the act nor the day of expiry counts.
  2. Which calendar. Public holidays are national, and sometimes regional. The same term, the same start date and the same regime produce different dates in Paris and in Strasbourg.
  3. Whether the date rolls over. A term expiring on a Saturday may be postponed to the next working day — under some regimes, in some jurisdictions.

Get any one of the three wrong and the output is still a plausible-looking ISO date. There is no runtime error to catch. That is exactly the failure profile an autonomous agent should not absorb into its own reasoning.

The counting rules are written law, not convention

These are not house conventions to be inferred from context; they are codified, and they differ by legal order.

Legal orderInstrumentDay of the actWeekend / holiday expiryMonths
France (civil procedure)Articles 641 and 642 of the Code de procédure civileDoes not countTerm extended to the next working day (art. 642)Expires on the day bearing the same day-of-month
European UnionRegulation (EEC, Euratom) No 1182/71Does not count (art. 3)Period ends at the last hour of the following working day (art. 3)If the day does not exist in the last month, the period ends on the last day of that month

Two independently drafted regimes, converging on the same three primitives — which is precisely why a generic date + N is wrong so often, and why the endpoint returns which rule it applied rather than only the result. Whether Regulation 1182/71 is still the version in force is itself a question you can put to GET /legal/eu-act.

The regime is the caller’s decision, and it is never inferred

The endpoint dates a term. It does not advise which term applies to your matter, nor which regime governs it. Ask for a deadline without a regime and you get a 400 that lists the seven admissible values instead of a plausible default:

{ "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" }
regimeCountsRollover
calendar_daysEvery day; no calendar is consulted at allNo
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

Refusing to guess is the whole point. A date computed under the wrong regime is indistinguishable, in the response, from a date computed under the right one — so the choice is pushed back to the caller, where the legal knowledge actually lives.

The call

A start date, a length, a regime, and the country whose holiday calendar applies. Every regime except calendar_days consults a calendar and therefore requires country.

GET /legal/deadline?start=2026-05-06&duration=5&regime=working_days&country=FR

Five working days from 6 May 2026 in France is 15 May, not 11 May — four days were skipped, and the response names all four:

{
  "data": {
    "due_date": "2026-05-15",
    "regime": "working_days",
    "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": { "country": "FR", "authority": "official", "as_of": "2026-07-29" }
  },
  "provenance": {
    "source": "official-holiday-calendars",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-29T00:00:00Z" }
  }
}

due_date is the answer. Everything beside it exists so the answer can be checked without trusting the service: an agent can log skipped_days and steps into its audit trail, and a human reviewing the file later can redo the count by hand in under a minute.

Two rules can stack on one term

A term in months from the 31st is where the end-of-month rule and the rollover rule meet. One month from 31 January 2026: day 31 does not exist in February, so the term lands on the 28th — a Saturday — and article 642 pushes it to the following Monday.

{
  "due_date": "2026-03-02",
  "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"
  ]
}

Both rules are named in steps, in the order they were applied. Note also what is absent: days_counted is not served for months and years, because a term in months counts no days and the service does not manufacture a number to fill a field.

Whose calendar, and on whose authority

Ten countries are covered. France comes from the holiday calendar published by the French State (the Etalab calendrier.api.gouv.fr dataset); BE, DE, ES, IE, IT, LU, NL, PL and PT come from an open community reference dataset (Nager.Date) that has no official standing. Every answer carries which one backed it, in data.calendar.authorityofficial or community_dataset. A community dataset never silently becomes published law inside an integration.

Regional calendars matter more than they look. The same request, run twice, differing only by subdivision:

RequestSkippeddue_date
start=2026-04-01&duration=3&regime=working_days&country=FRSat, Sun, Easter Monday2026-04-07
&subdivision=FR-ALSACE-MOSELLEGood Friday, Sat, Sun, Easter Monday2026-04-08

Good Friday is a public holiday under the local law of Alsace-Moselle (article L3134-13 of the Code du travail) and not elsewhere in France. That single day moves the deadline, and data.calendar.subdivision is echoed on the response so the answer always says which of the two calendars it used.

Holiday calendars are also not constants. In July 2025 the French government proposed removing two public holidays as part of the 2026 budget; the proposal was subsequently dropped. Either outcome is a reason not to freeze a holiday table into agent code: provenance.freshness.as_of tells you the date of the calendar dump that backed the answer, and it has its own refresh cycle, independent of the LEGI and EUR-Lex dumps behind GET /legal/article.

Out of coverage is a refusal, not a guess

Per the x402 golden rule, the agent pays for the answer to its question. A well-formed request on a covered calendar returns its due date — a 200. What the service cannot answer leaves the 200 range and is not billed, because a deadline computed on a guessed calendar is worse than no deadline:

{ "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 2033-01-05 is outside the loaded holiday calendar for `FR` (2015-01-01 to 2029-12-31 inclusive)" }

The coverage window is derived from the days actually present in the loaded calendar rather than declared, and both bounds are inclusive. A start date or a due date beyond it is a 404: days whose holiday status is unknown are never counted as ordinary days. Every refusal names what is covered, so the second call can succeed.

What it will not do

Three sentences travel in data.limits on every answer. They are the contract, not small print:

  • It does not choose the term or the regime. It dates a term; it does not advise which term applies or which regime governs it.
  • 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 ride on every answer precisely so that distinction cannot be lost downstream.

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

Where it sits in the x402 loop

The call follows the same pattern as every Invoket endpoint — discover, receive the 402, sign the chosen rail, replay:

  1. Discover the endpoint on the catalog and call it; receive the 402.
  2. Pay — sign and replay the request.
  3. Read due_date, and keep steps plus skipped_days in the audit trail.
  4. Branch — schedule against due_date; if the response carries authority: "community_dataset", decide whether that is good enough for the decision at hand.

The Quickstart walks the whole discover → 402 → pay → replay cycle with runnable snippets. Price and accepted rails are deliberately not pinned in this article: the catalog is the single source of truth for both, and it also states which endpoints currently carry a free trial call.

Two endpoints pair naturally with this one on either side of a due date:

  • GET /legal/article and GET /legal/eu-act — the text that sets the term, and whether it is still in force.
  • POST /invoice/late-payment — once a due date has passed, what the unpaid claim actually owes under Directive 2011/7/EU. /legal/deadline produces the date; /invoice/late-payment prices the breach of it.

Used for what it is — a deterministic, auditable date under a regime the caller chose — GET /legal/deadline removes date arithmetic from the list of things an agent has to be trusted with. For the full field reference, the seven regimes and the error codes, see the endpoint documentation; for how agents discover and call Invoket endpoints, see For agents.

Sources and attribution

The French public-holiday calendar is derived from the open dataset published by the French State under the Licence Ouverte / Etalab. The nine other national calendars come from the Nager.Date open reference dataset. Articles 641 and 642 of the Code de procédure civile are cited from the LEGI dataset made available by DILA on Légifrance.