Skip to content

Extracting Due Dates From Invoices That Don't State One

9 min read · updated August 11, 2026

A large share of invoices print payment terms and no due date. Deriving one is easy arithmetic on the wrong input: the terms tell you how many days, and almost nothing on the page tells you unambiguously what day to count from.

Why the field is empty

European invoicing standards treat the two as separate business terms. In EN 16931, the structured due date is BT-9 and the free-text payment terms are a different term entirely; a compliant invoice may carry either, and plenty of accounting systems only ever print the terms string. So due_date: null on a document that visibly says “Net 30” is not an extraction failure. The due date is genuinely not there, and your pipeline has to compute it.

That computation has three inputs: a number of days, a base date, and a calendar convention. Extractors reliably get the first one right and reliably get the second one wrong.

The base date is the hard half

“Net 30” means thirty days from something. Candidates on a single invoice regularly include:

  • The invoice date — the date of issue, Article 226(1) of the EU VAT Directive. The default assumption, and often right.
  • The tax point or supply date — Article 226(7), required when it differs from the issue date. On a month-end-billed service invoice these differ by days.
  • The delivery date — on goods invoices where terms read “30 days from delivery”.
  • Your date of receipt — not printed on the invoice at all. Terms reading “30 days from receipt of invoice” cannot be resolved from the document; the base date lives in your ingestion timestamp.

The difference matters more than the terms do. An invoice dated the 2nd, delivered on the 20th and received on the 27th has three plausible Net 30 answers spanning twenty-five days. So the extraction schema should carry the base explicitly rather than collapse it:

{
  "payment_terms_text": "30 days from date of delivery",
  "net_days": 30,
  "base": "delivery_date",      // invoice_date | tax_point | delivery_date | receipt_date
  "due_date": null,             // computed, not extracted
  "due_date_source": "derived"  // or "stated" when BT-9 was printed
}

Keeping due_date_source is worth the field. When a stated due date and a derived one disagree, you want to know which you used before somebody asks why a payment ran late.

The arithmetic, worked

Take an invoice dated 2026-01-31 with terms “2/10 net 30”, base = invoice date. Two dates come out of it:

invoice_date          = 2026-01-31
net_days              = 30
discount_days         = 10
discount_percent      = 2.0

discount_date = 2026-01-31 + 10 days = 2026-02-10
due_date      = 2026-01-31 + 30 days = 2026-03-02

Note what the second line is not: it is not “a month later”. Thirty calendar days from 31 January lands on 2 March in a non-leap year and 1 March in a leap year. Any implementation that adds a month, or that adds 30 days to a date parsed with the wrong day/month order — the case a date-field validation rule exists to catch — produces an answer that is wrong by one to three days, small enough to survive review and large enough to lose a discount.

Count in calendar days unless the document says otherwise. Business-day terms exist but are rare and are usually spelled out (“30 business days”); silently applying a business-day calendar to plain “Net 30” makes every due date late by about a third. A separate question is whether payment is *made* on a non-banking day, which is a treasury rule and not part of the invoice.

EOM, prox and the month-end cases

Three families of terms move the base date to the end of a month, and they are the ones a naive parser silently mishandles because the digits look the same.

  • Net 30 EOM — thirty days from the end of the invoice month. An invoice dated 2026-01-05 gives a base of 2026-01-31 and a due date of 2026-03-02, not 2026-02-04.
  • Net 15 MFI / “15th prox” — the 15th of the month following. An invoice dated 2026-01-05 is due 2026-02-15; one dated 2026-01-28 is also due 2026-02-15. Terms of this shape produce identical due dates for an entire month of invoices, which is a useful sanity signal that you parsed them correctly.
  • Cut-off variants — “25th prox, invoices after the 20th roll to the following month”. These carry a conditional and cannot be represented as a single integer. Store the raw text and route to review rather than approximate.

German and Dutch invoices print the same ideas in their own vocabulary — “30 Tage netto”, “3% Skonto 14 Tage”, “betaling binnen 30 dagen”. The parsing strategy for that long tail, and code for it, is in turning payment-terms text into structured fields.

When the invoice says nothing at all

Some invoices carry no due date and no terms. The correct behaviour is not to guess thirty days, and it is not to leave the record without a date either — it is to fall back to the agreed contract terms in your supplier master, and only then to a statutory default.

Those statutory defaults exist. Article 3 of Directive 2011/7/EU on combating late payment in commercial transactions, published by the European Union in 2011, provides that where the contract fixes no payment date, interest becomes due 30 calendar days after the debtor receives the invoice — and where goods or a verification procedure come later, the clock runs from the latest of receipt of the invoice, receipt of the goods, and completion of that verification. The same article caps contractually agreed periods between undertakings at 60 calendar days unless expressly agreed and not grossly unfair.

That is the shape of the rule, not legal advice, and member states implement it in their own law with their own variations. Use it to decide what your pipeline should do when a field is missing; ask somebody qualified what you owe.

Practically, that gives a resolution order worth encoding: stated due date, then derived from stated terms, then contract terms on the supplier record, then a flagged statutory fallback that a human sees. Every step down that ladder should be recorded in the extraction record, because the derived date is the one people query when a payment run looks wrong.