Skip to content

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.

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:

  • from and to — an inclusive date range, which takes precedence over year
  • year — shorthand for a whole calendar year, defaulting to the current one
  • periodicityDaily, Weekly, Monthly (the default), Quarterly or Annually

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. Pass expenses=true for purchases, and paid=true to 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 cost
  • Discount — 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.

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 bucket
  • GET /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. take returns 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. side is Customers (the default) or Suppliers.

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.

A product now stores its sale price both excluding and including tax, and returns both, along with the margin figures derived from them:

  • taxExcludedPrice and taxIncludedPrice
  • margin — the tax-excluded price less the purchase price, per unit
  • markupRate — 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.

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 steps
  • fr:200 to fr:228 and fr:501 for the French lifecycle statuses — fr:200 is Déposée, fr:212 is Encaissée, fr:213 is Rejetée
  • ppf:* for the public platform’s flows, and aoz:* 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.

GET /v1/Settings returns three new values:

  • sales.outstandingLimit — the default maximum outstanding balance for a customer that has no limit of its own
  • sales.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 full
  • eInvoicing.validateAddressesBeforeSubmit — whether both parties’ e-invoicing addresses are checked before an invoice is submitted

sales.marginRate is removed.