POST /invoice/late-payment
Turns “this invoice is late” into a number an agent can act on: the statutory interest due on an unpaid commercial claim under Directive 2011/7/EU on combating late payment, plus the fixed compensation for recovery costs, under the national transposition that applies.
The answer is not a single rate multiplied by a number of days. Interest is
computed tranche by tranche: the reference rate changes every half-year (1
January, 1 July), so a claim outstanding for eleven months crosses two or three
tranches at different rates. Each tranche is served with its reference rate,
its statutory rate, its days and its interest - interest_total is exactly
their sum, so the figure can be recomputed by hand.
The runtime is pure computation over a committed rate series - no network
call and no secret at request time. See the live
/catalog for the authoritative endpoint listing and
price.
Interest is simple, never capitalised, and the day count is calendar days on an
actual/365basis, restated indata.day_count_conventionon every answer. Interest runs from the day after the due date (art. 3(1)) to the payment date included.
x402 golden rule: the agent pays for the answer to its question. The
question is “what does this late invoice owe?” - so a well-formed claim gets a
200, billed, including when the answer is zero: paying on time returns
days_late: 0, total_due: 0 and a rationale citing art. 3(1). That is a
computed answer, not a failure. Only requests the service cannot answer - a
missing due date, a third country, a date outside the rate series - leave the
200 range and are not billed.
Request
POST with a JSON body. Set Content-Type: application/json. Unknown fields
are refused, never ignored.
POST /invoice/late-payment
Content-Type: application/json
{
"amount": "25000",
"currency": "EUR",
"country": "FR",
"due_date": "2025-08-31",
"paid_date": "2026-07-27"
}
| Field | Type | Required | Description |
|---|---|---|---|
amount | string | yes | Principal of the unpaid claim, plain decimal string, strictly positive |
currency | string | yes | ISO 4217 (XXX and XTS refused) |
country | string | yes | Member State whose transposition applies, ISO 3166-1 alpha-2 (EL accepted for GR) |
due_date | string | one of the three forms | Contractual due date |
invoice_date | string | one of the three forms | Invoice date, used with payment_terms_days or with the statutory default |
payment_terms_days | number | no | Agreed term in days, counted from invoice_date |
paid_date | string | no (defaults to today) | Date of payment, or of the assessment |
contractual_rate | string | no | Agreed annual rate in points - applied only if it exceeds the statutory rate |
Three ways to say when the payment period ended, and data.due_date_source
always says which one was used:
due_date_source | Supplied |
|---|---|
contractual_due_date | due_date |
payment_terms | invoice_date + payment_terms_days |
statutory_default | invoice_date alone - the national statutory period applies, and a note says so |
Supplying both due_date and payment_terms_days is not an error: the
stipulated due date wins and a note records that the term was ignored.
Supplying none of the three is a 400 missing_field: a due date is never
invented.
Covered transpositions
FR, DE, ES, IT, NL, BE, PT and PL carry their own national rule - margin,
fixed sum, statutory period, legal cap on payment terms, and their national
legal basis quoted in its own language. Any other Member State is served
the Directive minimum, and the response flags it as such with
rule.rule_source: "eu_minimum_fallback" - a fallback is never passed off as a
national rule.
country | rule_source | reference_basis | margin_points | Notes |
|---|---|---|---|---|
FR | national | ecb | 10 | Code de commerce, art. L441-10, L441-11, D441-5 |
DE | national | ecb | 9 | § 288 BGB - the Basiszinssatz base sits 0.88 pt below the ECB rate |
BE | national | ecb | 8 | The statutory rate is rounded up to the half point |
ES, IT, NL, PT | national | ecb | 8 | Own transposition, Directive margin |
PL | national | nbp | 10 | NBP reference rate, and a fixed sum tiered by claim size |
| Any other EU State | eu_minimum_fallback | ecb | 8 | Directive minimum, explicitly flagged |
A third country is refused (400 unsupported_country): the Directive
governs commercial transactions within the Union, and no rule is guessed
beyond it.
200 response - UnifiedResponse
{
"data": { ... },
"provenance": {
"source": "late-payment-snapshots",
"fetched_at": "2026-07-30T18:11:04Z",
"freshness": { "kind": "snapshot", "as_of": "2026-07-27T00:00:00Z" }
}
}
Fields of data
| Field | Type | Description |
|---|---|---|
claim | object | Echo of the principal and its currency |
due_date | string | The due date actually used |
due_date_source | string | Which of the three forms produced it |
paid_date | string | Payment or assessment date |
days_late | number | Calendar days from the day after the due date to the payment date included |
day_count_convention | string | calendar days, actual/365 - stated on every answer |
periods | array | The reason this endpoint exists: one tranche per boundary crossed |
interest_total | object | Exactly the sum of the tranches served |
flat_fee | object | Fixed compensation for recovery costs (art. 6), with its source |
total_due | object | Interest + fixed sum. null outside the euro - see below |
rule | object | The national rule actually applied, and its legal bases |
rationale | string | Why the count is not the nominal case. Present exactly when there is something to explain |
notes | array | Remarks on the request: ignored term, statutory default applied, agreed rate below the floor, term above the legal cap |
limits | array | Six constant sentences on what is not assessed. Served with every answer |
periods[] - one tranche per boundary crossed
| Field | Description |
|---|---|
from, to | The tranche, both bounds inclusive |
days | Days counted in it |
reference_basis | ecb or nbp - which published series the tranche rests on |
reference_rate | The reference rate of that half-year |
statutory_rate | The statutory rate in force in that State for that tranche |
applied_rate | The rate actually applied - the statutory one, or a higher agreed one |
rate_source | statutory or contractual |
interest | Interest of the tranche, rounded to the cent |
A new tranche opens on each half-year of the reference rate (1 January, 1
July) and on any change in the national transposition. For most States
statutory_rate is reference_rate + margin_points; where the transposition
says otherwise - the German Basiszinssatz, the Belgian rounding up to the
half point - the served statutory_rate follows the national rule, which
is why it is served per tranche rather than left to be recomputed.
flat_fee and total_due
The fixed sum of art. 6 is due as of right as soon as interest is due,
without any reminder: EUR 40 in every covered State (source: "flat"), tiered
by claim size in Poland since 2020 (source: "tiered"), and 0 with
source: "not_due" when nothing is late. Reasonable recovery costs actually
incurred beyond it (art. 6(3)) are not quantified here.
total_due is served only when the claim is in euros. The fixed sum is a
euro amount fixed by the Directive, so on a claim in another currency the field
is null and a note says why - no exchange rate is invented.
Example - a claim across three half-years
EUR 25,000 due on 31 August 2025, paid on 27 July 2026 in France. Three
tranches - one per half-year crossed, and the ECB reference rate did move on 1
July 2026 - each verifiable on its own (abridged: the constant limits[] are served in full):
{
"data": {
"claim": { "amount": "25000", "currency": "EUR" },
"due_date": "2025-08-31",
"due_date_source": "contractual_due_date",
"paid_date": "2026-07-27",
"days_late": 330,
"day_count_convention": "calendar days, actual/365",
"periods": [
{ "from": "2025-09-01", "to": "2025-12-31", "days": 122, "reference_basis": "ecb", "reference_rate": "2.15", "statutory_rate": "12.15", "applied_rate": "12.15", "rate_source": "statutory", "interest": "1015.27" },
{ "from": "2026-01-01", "to": "2026-06-30", "days": 181, "reference_basis": "ecb", "reference_rate": "2.15", "statutory_rate": "12.15", "applied_rate": "12.15", "rate_source": "statutory", "interest": "1506.27" },
{ "from": "2026-07-01", "to": "2026-07-27", "days": 27, "reference_basis": "ecb", "reference_rate": "2.40", "statutory_rate": "12.40", "applied_rate": "12.40", "rate_source": "statutory", "interest": "229.32" }
],
"interest_total": { "amount": "2750.86", "currency": "EUR" },
"flat_fee": { "amount": { "amount": "40", "currency": "EUR" }, "source": "flat" },
"total_due": { "amount": "2790.86", "currency": "EUR" },
"rule": {
"country": "FR",
"rule_source": "national",
"reference_basis": "ecb",
"margin_points": "10",
"flat_fee_eur": "40",
"default_payment_term_days": 30,
"max_payment_term_days": 60,
"legal_basis": [
{ "scope": "eu", "celex": "32011L0007", "query": "/legal/eu-act?celex=32011L0007&article=3", "reference": "Directive 2011/7/EU, art. 3 (interest for late payment, at the reference rate plus at least eight percentage points)" },
{ "scope": "eu", "celex": "32011L0007", "query": "/legal/eu-act?celex=32011L0007&article=6", "reference": "Directive 2011/7/EU, art. 6 (compensation for recovery costs: a fixed sum of at least EUR 40, due as of right)" },
{ "scope": "national", "reference": "Code de commerce, art. L441-10 (délai supplétif de 30 jours, taux BCE majoré de dix points, indemnité forfaitaire) et art. L441-11 (plafond de 60 jours), art. D441-5 (montant de l'indemnité : 40 EUR) — loi n° 2012-387 du 22 mars 2012, applicable aux contrats conclus à compter du 1er janvier 2013" }
]
},
"notes": []
}
}
122 + 181 + 27 = 330 days, and 1015.27 + 1506.27 + 229.32 = 2750.86. The
EU legal bases carry a ready-made query for
GET /legal/eu-act, served by the platform itself.
Example - paid on time, a billed zero
{
"data": {
"days_late": 0,
"periods": [],
"interest_total": { "amount": "0", "currency": "EUR" },
"flat_fee": { "amount": { "amount": "0", "currency": "EUR" }, "source": "not_due" },
"total_due": { "amount": "0", "currency": "EUR" },
"rationale": "payment on 2026-07-27 did not exceed the due date of 2026-07-31: art. 3(1) makes interest and the fixed recovery sum payable only once the payment period has been exceeded"
}
}
Zero is an answer: it is what lets an agent close a dispute rather than open
one. periods is empty rather than carrying a nil tranche, and flat_fee
says not_due rather than 0 without a reason.
Example - a Member State without its own rule
An Austrian claim of EUR 9,800, due 15 March 2026. The Directive minimum applies and says so:
{
"data": {
"days_late": 134,
"periods": [
{ "from": "2026-03-16", "to": "2026-06-30", "days": 107, "reference_basis": "ecb", "reference_rate": "2.15", "statutory_rate": "10.15", "applied_rate": "10.15", "rate_source": "statutory", "interest": "291.60" },
{ "from": "2026-07-01", "to": "2026-07-27", "days": 27, "reference_basis": "ecb", "reference_rate": "2.40", "statutory_rate": "10.40", "applied_rate": "10.40", "rate_source": "statutory", "interest": "75.39" }
],
"interest_total": { "amount": "366.99", "currency": "EUR" },
"total_due": { "amount": "406.99", "currency": "EUR" },
"rule": {
"country": "AT",
"rule_source": "eu_minimum_fallback",
"margin_points": "8",
"legal_basis": [
{ "scope": "eu", "reference": "Directive 2011/7/EU, art. 3 (interest at the reference rate plus eight percentage points, 30-day default period), art. 3(5) (60-day cap) and art. 6 (EUR 40 fixed sum) — transposition deadline of 16 March 2013" }
]
}
}
}
eu_minimum_fallback is a floor: the real Austrian rule may be more
generous to the creditor. The flag is there so an agent knows the difference
between “this is the national rule” and “this is the least the Directive
guarantees”.
Example - a claim outside the euro
A Polish claim of PLN 120,000. The interest is computed in PLN on the
NBP series; the fixed sum stays a euro amount, so total_due is null:
{
"data": {
"days_late": 193,
"periods": [
{ "from": "2026-01-16", "to": "2026-06-30", "days": 166, "reference_basis": "nbp", "reference_rate": "4.00", "statutory_rate": "14.00", "applied_rate": "14.00", "rate_source": "statutory", "interest": "7640.55" },
{ "from": "2026-07-01", "to": "2026-07-27", "days": 27, "reference_basis": "nbp", "reference_rate": "3.75", "statutory_rate": "13.75", "applied_rate": "13.75", "rate_source": "statutory", "interest": "1220.55" }
],
"interest_total": { "amount": "8861.10", "currency": "PLN" },
"flat_fee": { "amount": { "amount": "100", "currency": "EUR" }, "source": "tiered" },
"total_due": null,
"notes": [
"interest is computed in PLN, while the fixed recovery sum of art. 6 is denominated in euro: total_due is not served because no exchange rate is applied"
]
}
}
The Polish fixed sum is tiered by claim size (source: "tiered", EUR 100
here rather than EUR 40) - a national rule the Directive minimum would have
missed.
The notes that change the number
Four situations are recorded in notes[] rather than silently applied:
- an agreed rate below the statutory one - the statutory rate is a
public-policy floor (art. 7). The agreed rate is ignored,
rate_sourcestaysstatutory, and the note says so. An agreed rate above it is applied, tranche by tranche, withrate_source: "contractual"; - no term supplied - the national statutory period applies (30 days in the covered States), quoted with its national basis;
- an agreed term beyond the legal cap - a 90-day term where the cap is 60 is not refused: it is computed as supplied, with a note recalling that such a term may be void, in which case the statutory period applies. The service does not decide the validity of a contract clause;
- both a due date and a term - the stipulated due date is used and the term is ignored.
What this endpoint will not do
The six sentences in data.limits are served with every answer. Out of
scope: consumer claims (the Directive governs transactions between
undertakings and with public authorities), the sector-specific and
public-authority regimes, recovery costs above the fixed sum (art. 6(3)),
the limitation of the claim, judicial interest and other contractual
penalties, and any assessment of whether the claim itself is owed. It computes
what the law provides on the facts you declare; it does not litigate them.
Coverage of the rate series
The committed series runs from 2011-01-01 to the last published half-year,
and is never extrapolated: a due date beyond it is a
400 date_out_of_range naming the covered window - the rate of an unopened
half-year does not exist yet. A payment more than ten years after the due date
is refused as implausible_dates.
Errors
Typed 4xx responses are not billed, and faults are accumulated: one
400 lists every actionable issue in issues[].
| Status | code | issues[].code | Case |
|---|---|---|---|
| 400 | INVALID_INPUT | - | Body is not readable JSON, an unknown field, or a negative payment_terms_days |
| 400 | INVALID_INVOICE_INPUT | missing_field | None of the three ways of stating the due date was supplied |
| 400 | INVALID_INVOICE_INPUT | unsupported_country | Not an EU Member State |
| 400 | INVALID_INVOICE_INPUT | invalid_amount | amount is not strictly positive |
| 400 | INVALID_INVOICE_INPUT | invalid_decimal | amount or contractual_rate is not a plain decimal |
| 400 | INVALID_INVOICE_INPUT | invalid_currency | XXX or XTS |
| 400 | INVALID_INVOICE_INPUT | invalid_date | Not a real calendar date in YYYY-MM-DD form |
| 400 | INVALID_INVOICE_INPUT | date_out_of_range | A date outside the committed rate series |
| 400 | INVALID_INVOICE_INPUT | implausible_dates | Payment more than ten years after the due date |
| 500 | INTERNAL | - | Internal error (detail logged, not exposed) |
{
"code": "INVALID_INVOICE_INPUT",
"error": "invoice input is invalid: 1 actionable issue(s) listed in issues[]",
"issues": [
{ "code": "unsupported_country", "message": "US is not an EU member state: Directive 2011/7/EU governs commercial transactions within the Union, and no national rule is guessed outside it", "path": "country" }
]
}
{
"code": "INVALID_INVOICE_INPUT",
"error": "invoice input is invalid: 1 actionable issue(s) listed in issues[]",
"issues": [
{ "code": "date_out_of_range", "message": "no ecb reference rate is known for 2027-01-01: the committed series covers 2011-01-01 to 2027-01-01 (exclusive) and is never extrapolated", "path": "due_date" }
]
}
Attribution
The rules are those of Directive 2011/7/EU on combating late payment in
commercial transactions, as published on EUR-Lex - the cited articles are
queryable through GET /legal/eu-act - together with
the national transpositions quoted in rule.legal_basis (Code de commerce,
BGB, Decreto legislativo 231/2002, and their equivalents). Reference rates come
from a committed series of the European Central Bank refinancing rate and,
for Poland, of the Narodowy Bank Polski reference rate.
See also
POST /invoice/validate- is the invoice you are chasing conformant in the first place?GET /legal/deadline- date a procedural time limit (formal notice, court filing) once the debt is established.GET /company/events- whether the debtor is already in an insolvency proceeding, before you spend on recovery.GET /legal/eu-act- the text of the Directive articles cited inrule.legal_basis.- For agents - discovery surfaces, the live
/catalogand how settlement works.