Skip to content

Blog

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
  • periodicity — Daily, 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.

Changelog 2026-09-07

Your bank accounts are now in the API, metadata stops overwriting itself, and payloads we had started refusing are welcome again.

Bank accounts and their transactions are now part of the API.

Accounts:

  • GET /v1/BankAccounts and GET /v1/BankAccounts/{id}
  • POST /v1/BankAccounts to create one, PUT /v1/BankAccounts/{id} to update it
  • DELETE /v1/BankAccounts/{id}
  • POST /v1/BankAccounts/SetAsMain/{id} — moves the main-account designation from whichever account holds it, since exactly one account is main at a time

Transactions, read-only:

  • GET /v1/BankAccounts/{id}/Transactions — paged, with from, to, searchTerm, hideExcluded and hideReconciliated
  • GET /v1/BankTransactions/{id}
  • POST /v1/BankTransactions/Exclude/{id} and POST /v1/BankTransactions/Include/{id} — set a transaction aside so it stops being offered for reconciliation, or bring it back

An account synchronized from a provider mirrors what that provider reports, so Altoviz is not its system of record and neither are you.

Every account carries a provider object — type, accountId, accountStatus, bankName — which is null on an account you keep by hand, and a connected flag that says the same thing. One null check tells you whether an account is yours to write to.

  • PUT and DELETE on a connected account return 400. Disconnect it in Altoviz first.
  • The provider fields are never writable, on any account. They are absent from the create and update bodies entirely.

Setting the main account and excluding or including a transaction still work on a connected account: those are Altoviz’s own bookkeeping, not something the provider owns.

Deleting is deliberately hard to do by accident. Beyond the connected check, DELETE returns 409 when the account holds any transaction already reconciled with a receipt or a payment, and 400 when the account is the main one. What gets through is an account created by mistake or never used — which is the only kind you should be deleting through an API, because deletion also removes the account’s accounting journal and every entry in it.

metadata is now available on customers and products. It was already stored and already used — the WooCommerce import writes woocommerce_product_id, Quickbooks writes qbo_id — you just could not read it back.

More importantly, metadata is now a patch everywhere the API carries one:

  • keys you send are added or updated
  • keys you leave out keep whatever they held
  • a key is removed only when you send it as null
  • "" stores an empty value, it does not remove anything
  • omitting the property entirely leaves the whole bag untouched

The bag is shared. Your integration is not the only thing writing to it, and replacing it wholesale meant sending your own single key silently dropped everyone else’s.

⚠️ Breaking change: if you relied on omitting a key to remove it, send that key as null instead. This affects invoices, quotes, credits, receipts, colleagues, MarkAsPaid and MarkAsRefunded, which previously replaced the whole bag.

Find accepted an internal id and nothing else — the one key a document created inside Altoviz never has. So documents made in the app were invisible to it.

  • GET /v1/SalesQuotes/Find, /v1/SalesInvoices/Find and /v1/SalesCredits/Find now take a number alongside internalId, matching customers and products. When both are given, internalId wins.

A draft carries a provisional number from its own sequence (000001) until finalization assigns the real one (FA001000), so a search by number can match either.

GetByInternalId also spread beyond the three resources that had it:

  • GET /v1/Products/GetByInternalId/{internalId}
  • GET /v1/Receipts/GetByInternalId/{internalId}
  • GET /v1/SalesQuotes/GetByInternalId/{internalId}, and the same for SalesInvoices and SalesCredits

Sale documents were the only place in the API spelled without one. /v1/Exports/SalesInvoices always had it; /v1/SaleInvoices did not.

The canonical routes are now /v1/SalesInvoices, /v1/SalesQuotes and /v1/SalesCredits.

Nothing breaks. Every /v1/Sale* route is still served, returns exactly the same result, and is simply flagged deprecated in the specification, naming the route that replaces it. Move when it suits you.

Some payloads that had worked for years started coming back 400. Loosely-typed clients send what they send, and we had quietly narrowed what we accept. That is fixed, and now guarded by a test that re-types every field of every published model and asserts we still accept whatever we used to.

Accepted again:

  • a number where a string is declared — "woocommerce_order_id": 3587755
  • "true", "1", "0" or "" where a boolean is expected
  • "" where an optional number, date or enum is expected

⚠️ One exception, on purpose: a quoted number carrying a group separator, like "1,5", is now refused with a 400 naming the field. It used to be read as 15 — a silent factor of ten, on money. "1.5", "1000" and 1000 are unaffected.

Changelog 2026-08-17

E-invoicing lands in the API, and Altoviz is now reachable from your terminal, your automation platform, and your AI assistant.

The 2026 French e-invoicing reform is now visible through the API.

Invoices carry their platform status:

  • eInvoicingStatus — where the document stands on the network, from ApiUploaded to FrAccepted, FrDisputed or FrPaymentReceived (55+ status codes covering the API, PDP, PPF and Altoviz-side lifecycles)
  • eInvoicingInvoiceId — the identifier assigned by the platform
  • eInvoicingProviderId — the PDP that handles the document

Settings expose a new eInvoicing section so you can drive the whole flow:

  • profile — Standard or Advanced
  • autoSubmitInvoicesOnFinalize and validateBeforeSubmit
  • autoAcknowledgeReceivedInvoices and autoProcessTerminalStatuses
  • autoEmitPaymentSent, autoEmitPaymentReceived and autoCreateReceiptFromIncomingPayment
  • autoSendEReporting
  • includeTextLinesInXml

And two companions: sales.customersLiableToEInvoicing, plus an e-invoicing readiness report already available since June.

Finalizing is irreversible, and a rejected e-invoice is a bad way to find out something was missing. Two new endpoints let you ask first:

  • POST /v1/SaleInvoices/CheckEInvoicing/{id}
  • POST /v1/SaleCredits/CheckEInvoicing/{id}

They render the Factur-X / CII e-invoice, submit it to the platform’s validator, and return the findings. Nothing is finalized, nothing is transmitted.

The result gives you three ways to read the outcome:

  • isValid — the verdict, and the one to trust: a document can be non-conformant while every finding is only a warning, because the French BR-FR rules are reported as warnings
  • findings — structured entries with a severity (Error, Warning), a source telling you where to fix it (Application, Directory, Platform), a French text, and, when the platform reported one, the location in the generated XML and the validator name
  • messages — the same findings flattened to one-line strings, for a quick display

Draft documents only: a finalized one returns 409.

Documents now tell the full story of their own lifecycle.

On invoices:

  • cancelledCreditId / cancelledCreditNumber — the credit this invoice was issued to offset

On credits:

  • isCancelled and cancellationInvoiceId / cancellationInvoiceNumber — the invoice that cancelled this credit
  • replacedBy — the corrected credit that supersedes this one

GET /v1/SaleInvoices and GET /v1/SaleCredits gained two tri-state filters built on the new InclusionFilter type — Excluded (the default when the parameter is omitted), Only, or All:

  • Cancelled — hide, isolate, or include cancelled documents
  • Processed — same, for documents whose terminal e-invoicing status has been taken into account

⚠️ Breaking change: the boolean IncludeCancelled parameter on GET /v1/SaleInvoices is gone. Replace IncludeCancelled=true with Cancelled=All.

Paying an invoice or refunding a credit can finalize it on the fly. You now decide which date it gets:

  • finalizationDate — the date the document is finalized on, defaulting to the document’s own date, and distinct from the payment or refund date
  • dateAdjustment — None, MinimumDate, or Today, to let the API pick a valid date for you

Both are available on the request bodies of POST /v1/SaleInvoices/MarkAsPaid and POST /v1/SaleCredits/MarkAsRefunded, and as query parameters on POST /v1/SaleInvoices/Finalize/{id} and POST /v1/SaleCredits/Finalize/{id}.

Two new read-only endpoints for home-care businesses:

  • GET /v1/HomecareServices/activities — the SAP activities, each with the TSA group it belongs to
  • GET /v1/HomecareServices/tsa-groups — the TSA groups (regroupements)
  • vat.vatRegime — Franchise, Simplified or Normal
  • company.summaryHtml — the rich company description
  • general.autoCollapseMenu
  • Email styling got finer grained: textColor, outerColor, buttonColor and buttonTextColor replace the single foreColor
  • Suppliers now have an active flag, like customers

⚠️ Breaking change: Annually was removed from VatDeclarationPeriodicity. Only Monthly and Quarterly remain.

altoviz is a self-contained CLI wrapping the REST API — customers, suppliers, invoices, quotes, products, receipts, and more, without leaving the shell.

  • No runtime required: a single binary for macOS, Linux and Windows
  • 9 output formats: table, JSON (pretty, compact or colored), YAML, Markdown, CSV (European or American) and TSV
  • Shell completions for bash, zsh, fish and PowerShell
  • Auth via environment variable, config file or --api-key
  • Scriptable: pipe JSON in with --file -, pick columns with --columns, page through with --all-pages

One command line can often solve daily life problems

Terminal window
# Fetch a single customer as JSON
altoviz customer get 42 --output json
# Export this year's invoices to CSV
altoviz export invoices --from 2026-01-01 --to 2026-12-31 --format EuropeanCsv --out invoices.csv

Install it with Homebrew, Chocolatey, WinGet, the Debian and Fedora packages, or the one-liner installer.

The Altoviz MCP Server connects ChatGPT, Claude, VS Code, Cursor or any other Model Context Protocol client straight to your account. It is remote — nothing to install.

  • Server URL: https://mcp.altoviz.com
  • Transport: Streamable HTTP and SSE
  • Authentication: OAuth 2.0, signing in with your Altoviz API key

It covers invoicing, contacts, catalogue, expenses, statistics, exports and webhooks, and it is listed in the official MCP Registry.

Automation guides are here for the three major platforms — Zapier, Make and n8n. Altoviz is the first French invoicing app for small businesses to integrate with all three.

Changelog 2026-06-02

Tons of new APIs were added and Altoviz Developer Hub is now running on steroid.

Statistic APIs expose the numbers used in the app dashboards like :

  • Monthly sales and expense breakdown for a given year​
  • Sales turnover comparison: current year, previous year, current month, previous month, and same month last year​
  • Expense turnover comparison: current year, previous year, current month, previous month, and same month last year
  • Micro-business sales turnover comparison (paid invoices only): current year, previous year, current month, previous month, and same month last year
  • Micro-business expense turnover comparison (paid expenses only): current year, previous year, current month, previous month, and same month last year
  • All-time total turnover
  • Turnover evolution over one or more years, broken down by month
  • E-invoicing readiness: suppliers and customers configured, and those with issues

Export APIs will allow you to export the most useful data from the app in the format you need.

Available data are :

  • Bank transactions
  • Customers
  • Expenses
  • Expenses reports
  • Invoices
  • Products
  • Purchases
  • Quotes
  • Receipts
  • Settlements
  • Suppliers

Formats are :

  • JSON
  • Microsoft Excel
  • American CSV
  • European CSV
  • TSV
  • Markdown

Each export was carefully built to facilitate further data analysis. They have temporal columns and relational data out-of-the-box.

We’re now using a whole new website management tool that will ease how we publish content and how fast it is : We moved from Docusaurus to Starlight.

Starlight is made with Astro :

  • it has a better architecture and principles
  • it is easier to customize for our needs
  • its community is more vibrant

Changelog 2025-08-04

We introduce a whole new API reference page, easier than ever to discover and experiment the Altoviz API.

New API reference page

The new API reference page brings some important new features :

  • an easier way discovery all the possibilities offered by the API, thanks to a whole new layout
  • support for light and dark theme
  • a dedicated search engine API search engine
  • more supported languages for the examples
  • a ability the live test the API from your browser Execute API from your browser