THE EXACT DATE IS NOT PREDICTABLE. Across 36,642 held-out invoices, the best of five methods hits the exact payment day 18.6% of the time (gradient boosting, snapped to the payment-run weekday). The category sells this as a solved problem; on real data it is wrong more than four times in five, and the honest output is a distribution rather than a date.
The payment date is not predictable — and the payer's calendar beats the model
On 183,269 real invoices from a purchase-to-pay ledger, how often can the exact payment date be predicted, and how much of that comes from the model rather than from the payer's calendar?
What the analysis found, including the results that went against us
Each of these came out of the run. None has been softened.
Settlements by weekday
Share of invoice settlements falling on each weekday. Settlement is heavily concentrated on one day because the payer runs payments on a schedule.
run.py section 3: share of clearing events falling on each weekday.
MACHINE LEARNING ADDS 0.1 DAYS OVER LOOKING UP WHAT THIS CUSTOMER DID LAST TIME. A per-vendor median lag gives MAE 13.4 days. Gradient boosting on ten features, temporally split, gives 13.3. That gap is the entire contribution of the model, and it is the comparison vendor material omits — the baseline is not a strawman, it is what a competent AP clerk already does.
How long invoices actually take
Distribution of how many days invoices actually took to clear, in weekly buckets. The spread is wide and right-skewed, which is why a single predicted date carries so little information.
run.py section 1: invoices cleared, by week of delay.
THE PAYER'S CALENDAR IS WORTH MORE THAN THE MODEL. 75.5% of settlements land on Thursday and 0.2% fall at the weekend, because a finance function runs payments on a schedule rather than continuously. Snapping any prediction to that weekday raises the exact-date hit rate by 10.3 points and costs nothing to implement. Knowing your customer's payment run beats modelling their behaviour.
Accuracy by tolerance band
Accuracy of a per-vendor lookup against gradient boosting at four tolerance bands. The two lines are close everywhere, which is the finding.
run.py sections 2 and 4: per-vendor lookup against gradient boosting.
THE STATED INTERVAL DOES NOT COVER. A quantile model asked for an 80% prediction band delivers 64% realised coverage on held-out invoices, with a median width of 27 days. A treasury team sizing a facility on that band is short of cover 16 percentage points more often than the number implies.
DROPPING THE UNPAID INVOICES FLATTERS EVERY FIGURE. 13.3% of received invoices never clear inside the window, and they are not missing at random — they are the slow tail. Complete-case analysis puts the median at 42 days; admitting the censored cases at the minimum duration they are known to have reached moves the median to at least 40 days, a shift of -2 days. That is a lower bound, not an estimate, and it moves in only one direction.
THE THING BEING PREDICTED IS NOT STABLE. In the UK statutory register, 7,897 companies have filed at least four times. Their own reported average time to pay swings by a median of 17 days between their own filings, and 56.9% swing by more than a fortnight. A forecast keyed on 'this customer pays in N days' is keyed on a number that is not stable at six-month resolution, in a panel of 10,224 companies quite separate from the ledger above.
A TEMPORAL SPLIT IS NOT OPTIONAL HERE. The model is trained on invoices received up to 2018-09-24 and tested only on later ones, so it never sees the future of the payer it is predicting. 291 test invoices belong to vendors absent from training and fall back to the global median — a shuffled split would have hidden both effects and reported a better number.
Full results tables
What each method achieves
| Method | MAE (days) | Exact day | Within 7 days | Within 14 days |
|---|---|---|---|---|
| Global median lag | 21.7 | 1.1% | 14.9% | 30.8% |
| Per-vendor median | 13.4 | 4.9% | 43.5% | 68.1% |
| Per-vendor + weekday snap | 13.6 | 15.2% | 49.0% | 70.4% |
| Gradient boosting | 13.3 | 4.1% | 44.7% | 67.9% |
| Gradient boosting + weekday snap | 13.2 | 18.6% | 53.0% | 71.2% |
Where the invoices go
| Stage | Count | Share of received |
|---|---|---|
| Purchase-order items in the log | 251,734 | — |
| Invoice received | 211,379 | 100.0% |
| Cleared inside the window | 183,293 | 86.7% |
| Never cleared inside the window | 28,086 | 13.3% |
| Usable after excluding negative and >365d lags | 183,269 | 86.7% |
Do companies pay at a stable speed?
| Measure | Value |
|---|---|
| Companies with four or more filings | 7,897 |
| Median swing in own reported average | 17 days |
| Companies whose own average swings by over 14 days | 56.9% |
| Companies whose own average swings by over 30 days | 20.7% |
Limitations
Stated by the analysis, not added afterwards. A project without these is not finished.
- This is one corporate group's accounts-payable ledger: four buying entities, one industry, one country, roughly two years. The payment-run weekday is a fact about this group's finance function, not a law of business. The UK panel is included precisely because it is a separate population, but it measures self-reported averages rather than invoice-level timing.
- The analysis is purely predictive and nothing here is causal. The log records no dunning calls, no collection actions, no discount offers and no disputes, so it cannot say why an invoice was paid when it was, nor what would happen if anything were changed.
- This is a buyer's purchase-to-pay ledger read from the vendor's point of view. 'Clear Invoice' is the buyer's clearing event, which is the closest observable to the day the supplier was paid but is not identical to value landing in the supplier's account.
- The censoring correction is a bound rather than an estimate. Treating 28,085 uncleared invoices as having lasted at least until the end of the window gives a median floor, not a median. A survival model would give a point estimate at the cost of a parametric assumption this file cannot check.
- The UK register is a live statutory service that grows continuously and accepts amended filings. Every figure from it is computed on filings dated 2026-08-08 or earlier, and the file's digest is asserted at load, so a later re-run reproduces the published window rather than silently reporting a different one.
- Exact-day accuracy is reported against calendar days, so an invoice cleared one working day late across a weekend counts as three days out. This is the right convention for cash management, where the calendar is what matters, but it is harsher than a working-day metric and figures here are not comparable to studies using one.
Data: BPI Challenge 2019 purchase-to-pay event log, CC BY 4.0. 1,595,923 rows, 2018-01-01 to 2019-02-28.
Libraries and methods this analysis used
Read from this project's own run.py when the page was built — 489 lines of it. Not a list of everything we know; a list of what this analysis imports and calls.
12 names from pandas appear in this analysis.
- Categorical
- agg
- assign
- astype
- dropna
- fillna
- groupby
- idxmax
- reindex
- sort_values
- to_numeric
- value_counts
5 names from NumPy appear in this analysis.
- concatenate
- histogram
- median
- random
- round
1 names from scikit-learn appear in this analysis.
- HistGradientBoostingRegressor
How every number on this page is checked
A script deletes each result file, re-runs the project and diffs the output. If a headline figure moves, the check fails, and the page does not ship. That is the only reason to believe anything on this page.
Running this method on your own data
The method above transfers; the result will not. Send us a extract and we will tell you what is forecastable in it and what is not, before anyone signs anything.