Changelog 2026-09-14
Statistics now cover any period you ask for, products finally know both of their prices, and e-invoicing statuses speak the platform’s language.
Statistics, over any period
Section titled “Statistics, over any period”The statistics endpoints used to think in calendar years and months. They now take a date range and a bucket size, like the dashboard does.
Every endpoint that covers a period accepts the same three parameters:
fromandto— an inclusive date range, which takes precedence overyearyear— shorthand for a whole calendar year, defaulting to the current oneperiodicity—Daily,Weekly,Monthly(the default),QuarterlyorAnnually
Each bucket carries its own range, and a partial flag set when the requested range clipped it. A March bucket in a range ending on the 10th holds ten days of activity, so do not compare it with a full February at face value.
New endpoints:
GET /v1/Statistics/TurnoverComparison— turnover over a period against the same period one year earlier and against the period of equal length just before it. Passexpenses=truefor purchases, andpaid=trueto count what was settled rather than what was invoiced.GET /v1/Statistics/CashFlowByPeriodicity— receipts, expenses and profits, each as settled, outstanding and projected. Every list shares the same buckets, so index N is the same period throughout.
GET /v1/Statistics/TurnoverEvolution follows the same model. It takes from, to, year and periodicity, and compare (0 to 2) returns the same period one and two years back as extra series. It can also break down two new dimensions through type:
Margin— what the lines brought in, less what their goods costDiscount— the gap between the gross amount and what was actually invoiced, line and document discounts included
⚠️ Breaking change: TurnoverEvolution now returns a single TurnoverEvolutionResult object instead of an array of years, and its years parameter is replaced by compare. The series are in series, the requested period first.
⚠️ Breaking change: these endpoints are removed, replaced by the ones above:
| Removed | Use instead |
|---|---|
GET /v1/Statistics/SalesTurnoverStatistics |
TurnoverComparison |
GET /v1/Statistics/ExpensesTurnoverStatistics |
TurnoverComparison?expenses=true |
GET /v1/Statistics/MicrobusinessSalesTurnoverStatistics |
TurnoverComparison?paid=true |
GET /v1/Statistics/MicrobusinessExpensesTurnoverStatistics |
TurnoverComparison?expenses=true&paid=true |
GET /v1/Statistics/StatsByMonth |
CashFlowByPeriodicity, or TurnoverEvolution for invoiced sales and expenses |
For a micro-business, paid is always applied: it is taxed on what it collects, not on what it invoices. Check company.isMicroBusiness in GET /v1/Settings before reading the numbers.
Who owes you, and how late
Section titled “Who owes you, and how late”Four endpoints answer the questions you ask before picking up the phone.
GET /v1/Statistics/UnpaidInvoices— the aged balance of what customers owe you, as totals per age bucketGET /v1/Statistics/UnpaidExpenses— the same for what you owe suppliers. Subtract one from the other for a net position.GET /v1/Statistics/TopOverdueCustomers— customers with overdue payments, ranked by amount.takereturns 1 to 20, 5 by default.GET /v1/Statistics/PaymentDelay— how long payments actually take over a period, from the document date and from the due date, plus the share of the amount paid late.sideisCustomers(the default) orSuppliers.
An aged-balance bucket is keyed by period: negative is overdue, 0 is due today, positive is upcoming. The steps are 1, 7, 15, 30, 60 and 90 days, so -7 means more than 90 days late.
TopOverdueCustomers returns the age of each customer’s oldest unpaid payment and lastReminderOn, the date of the last reminder sent to them. null means they were never chased, which is not the same as chased and still not paying.
For PaymentDelay, read medianDaysToPayment and medianDaysLate rather than the averages. A handful of very late payers can drag the mean to a month while the typical invoice is paid on time.
Products, with both prices
Section titled “Products, with both prices”A product now stores its sale price both excluding and including tax, and returns both, along with the margin figures derived from them:
taxExcludedPriceandtaxIncludedPricemargin— the tax-excluded price less the purchase price, per unitmarkupRate— the margin as a percentage of the purchase price (FR « taux de marge »)marginRate— the margin as a percentage of the sale price (FR « taux de marque »)
margin, markupRate and marginRate are computed on every save. A value you send for them is ignored.
Two fields are deprecated as a result:
| Deprecated | Use instead |
|---|---|
unitPrice |
taxExcludedPrice |
isUnitPriceTaxIncluded |
taxIncludedPrice, to send a tax-included price |
⚠️ Behaviour change on read: unitPrice is now always the tax-excluded price, and isUnitPriceTaxIncluded is always false. unitPrice used to hold whichever price the product was entered in, so for a product priced tax-included it now returns a different number. If your code read the flag before using the price, the result is the same. If it assumed the price included tax, read taxIncludedPrice instead.
Writing works as before. unitPrice on its own is read as tax-excluded, and isUnitPriceTaxIncluded: true still means the price you send includes tax.
Markup is not margin
Section titled “Markup is not margin”Document lines had a marginRate that divided the margin by the purchase price. That ratio is a markup rate, and products now have a real marginRate that divides by the sale price. Both could not share one name.
⚠️ Breaking change: on quote, invoice and credit lines, marginRate is renamed markupRate. The value is unchanged. Only the name is new.
E-invoicing statuses, as the platform names them
Section titled “E-invoicing statuses, as the platform names them”eInvoicingStatus on invoices returns the code defined by the e-invoicing platform, not an internal name:
api:uploaded,api:validated,api:sent, and so on, for the access point’s own stepsfr:200tofr:228andfr:501for the French lifecycle statuses —fr:200is Déposée,fr:212is Encaissée,fr:213is Rejetéeppf:*for the public platform’s flows, andaoz:*for statuses added by Altoviz
⚠️ Breaking change: if you compared this field to names like FrSubmitted or ApiSent, switch to the codes. The full list is in the EInvoicingStatusCode schema.
One status is new: aoz:importerror marks a received invoice that could not be turned into an expense yet, because its Factur-X could not be read or its supplier could not be matched. It is retried automatically, and it is replaced by the next fr:* status the platform sends.
Settings
Section titled “Settings”GET /v1/Settings returns three new values:
sales.outstandingLimit— the default maximum outstanding balance for a customer that has no limit of its ownsales.invoices.invoiceZeroQuantityLines— whether invoicing a quote brings along lines with nothing left to invoice, such as a zero quantity or a line already invoiced in fulleInvoicing.validateAddressesBeforeSubmit— whether both parties’ e-invoicing addresses are checked before an invoice is submitted
sales.marginRate is removed.