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/365 basis, restated in data.day_count_convention on 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"
}
FieldTypeRequiredDescription
amountstringyesPrincipal of the unpaid claim, plain decimal string, strictly positive
currencystringyesISO 4217 (XXX and XTS refused)
countrystringyesMember State whose transposition applies, ISO 3166-1 alpha-2 (EL accepted for GR)
due_datestringone of the three formsContractual due date
invoice_datestringone of the three formsInvoice date, used with payment_terms_days or with the statutory default
payment_terms_daysnumbernoAgreed term in days, counted from invoice_date
paid_datestringno (defaults to today)Date of payment, or of the assessment
contractual_ratestringnoAgreed 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_sourceSupplied
contractual_due_datedue_date
payment_termsinvoice_date + payment_terms_days
statutory_defaultinvoice_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.

countryrule_sourcereference_basismargin_pointsNotes
FRnationalecb10Code de commerce, art. L441-10, L441-11, D441-5
DEnationalecb9§ 288 BGB - the Basiszinssatz base sits 0.88 pt below the ECB rate
BEnationalecb8The statutory rate is rounded up to the half point
ES, IT, NL, PTnationalecb8Own transposition, Directive margin
PLnationalnbp10NBP reference rate, and a fixed sum tiered by claim size
Any other EU Stateeu_minimum_fallbackecb8Directive 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

FieldTypeDescription
claimobjectEcho of the principal and its currency
due_datestringThe due date actually used
due_date_sourcestringWhich of the three forms produced it
paid_datestringPayment or assessment date
days_latenumberCalendar days from the day after the due date to the payment date included
day_count_conventionstringcalendar days, actual/365 - stated on every answer
periodsarrayThe reason this endpoint exists: one tranche per boundary crossed
interest_totalobjectExactly the sum of the tranches served
flat_feeobjectFixed compensation for recovery costs (art. 6), with its source
total_dueobjectInterest + fixed sum. null outside the euro - see below
ruleobjectThe national rule actually applied, and its legal bases
rationalestringWhy the count is not the nominal case. Present exactly when there is something to explain
notesarrayRemarks on the request: ignored term, statutory default applied, agreed rate below the floor, term above the legal cap
limitsarraySix constant sentences on what is not assessed. Served with every answer

periods[] - one tranche per boundary crossed

FieldDescription
from, toThe tranche, both bounds inclusive
daysDays counted in it
reference_basisecb or nbp - which published series the tranche rests on
reference_rateThe reference rate of that half-year
statutory_rateThe statutory rate in force in that State for that tranche
applied_rateThe rate actually applied - the statutory one, or a higher agreed one
rate_sourcestatutory or contractual
interestInterest 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_source stays statutory, and the note says so. An agreed rate above it is applied, tranche by tranche, with rate_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[].

Statuscodeissues[].codeCase
400INVALID_INPUT-Body is not readable JSON, an unknown field, or a negative payment_terms_days
400INVALID_INVOICE_INPUTmissing_fieldNone of the three ways of stating the due date was supplied
400INVALID_INVOICE_INPUTunsupported_countryNot an EU Member State
400INVALID_INVOICE_INPUTinvalid_amountamount is not strictly positive
400INVALID_INVOICE_INPUTinvalid_decimalamount or contractual_rate is not a plain decimal
400INVALID_INVOICE_INPUTinvalid_currencyXXX or XTS
400INVALID_INVOICE_INPUTinvalid_dateNot a real calendar date in YYYY-MM-DD form
400INVALID_INVOICE_INPUTdate_out_of_rangeA date outside the committed rate series
400INVALID_INVOICE_INPUTimplausible_datesPayment more than ten years after the due date
500INTERNAL-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 in rule.legal_basis.
  • For agents - discovery surfaces, the live /catalog and how settlement works.