Skip to main content

Update a draft invoice

PATCH 

/api/v1/invoices/:id

Update a draft invoice by ID. Only invoices in "draft" lifecycle state can be updated.

This is a complete replacement operation: all child records (parties, lines, tax subtotals, payment means, notes, allowance charges, invoice references) are cleared and rebuilt from the provided payload.

Before the invoice is rebuilt, the payload is completed with the same company-side defaults as POST .../invoices - party_id resolution against the company directory, a company-side party default when the payload omits it (never overwriting a party entry the caller does supply), item_notes defaults on sales, and payment_means defaults (company bank accounts, or the buyer's factor account for a confidentially factored customer) on both directions. This is a behavior change for existing integrations: a PATCH that omits item_notes or payment_means now refills them from the company instead of leaving the invoice with none. The same guards run too, among them the ISO 4217 currency guard documented on POST .../invoices: currency_code (BT-5), tax_currency_code (BT-6) and each tax_subtotals[].currency_code are matched case-sensitively against the vendored code lists, and an unlisted value returns 422 without writing anything. An omitted BT-5 leaves the invoice's existing currency in force and is never refused. The VAT breakdown coherence guard documented there runs on this verb too, and here it is judged against the EFFECTIVE totals rather than the payload's: on direction: "sales", the sum of tax_subtotals[].amount_without_taxes is reconciled with total_amount_excluding_taxes and the sum of tax_subtotals[].vat_amount with total_tax_amount, within the 0.01 tolerance of PPF rule G1.53, each total read from the payload when its key is present and from the persisted invoice when it is omitted, and a gap beyond the tolerance returns 422 without writing anything. Reading the payload alone was wrong on this verb: the tax_subtotals sent REPLACE the document's wholesale while a total whose key is absent keeps its persisted value, so a PATCH carrying only a new ventilation left the totals untouched, fell out of the rule's scope, and persisted the very incoherence the guard exists to refuse. So does the SIREN conversion: a party filled from a directory record whose SIRET is declared under scheme 0009 is written with the SIREN of the legal unit under scheme 0002 (BR-FR-11 / BT-47), while a legal_registration_id sent explicitly on the entry is never converted. payment_means defaults resolve against the invoice's existing currency_code when the payload omits it, not EUR. They are resolved from the payload's buyer ONLY: because this endpoint replaces every party, omitting parties leaves the invoice with no buyer, and no payment means are emitted in that case rather than carrying over the destroyed buyer's bank account.

The already-paid coherence guard documented on POST .../invoices runs on this verb too, judged against the EFFECTIVE values like the VAT breakdown guard: invoicing_process_id, profile_id, the totals, due_date and issue_date are each read from the payload when the key is present and from the persisted invoice when it is omitted. So a PATCH that changes the total of a B2 / S2 / M2 invoice without restating prepaid_amount returns 422, and a PATCH that moves the invoice back to the B1 / S1 / M1 family leaves it out of the guard's scope.

Authorization is based on the OAuth application's tenant access to the invoice's workspace.

Request​

Responses​

The updated invoice, rebuilt from the payload with company-side defaults reapplied for any parties, item_notes, or payment_means the payload omitted.