Update Invoice
PATCH /accounting/invoices/{id}
Group: Accounting › Invoices · Operation ID: updateInvoice
Updates the invoice with the given identifier. Only the fields in the request body change. Use the invoice's id, not its invoiceNumber.
Edits an existing invoice. The invoice is named by the :id path segment. The response contains that id and nothing else, so read the invoice back with GET accounting/invoices/:id to see the recalculated totals.
Four header fields can be edited: invoiceDate, paymentTerm, customerMessage and purchaseOrderOverride, plus two fields on each line, description and dutiesAndCustomsAmount. Everything else is determined by the sales order and the billing run. Amounts, tax, the set of lines, and the delivery status the sending pipeline owns are all read-only here. Addresses and the invoice email cannot be edited.
Every field is omit-means-unchanged. Clearing is not uniform. purchaseOrderOverride treats an empty string as clear it and fall back to the sales order's PO references, while paymentTerm, customerMessage and invoiceDate ignore an empty value rather than storing it, so customerMessage cannot be cleared through this endpoint at all.
Changing invoiceDate re-derives the due date from the payment term and moves the invoice's tax period, so it is not a cosmetic edit.
Lines are addressed by id, inside updateLines. A line is matched only when it belongs to this invoice. A line id from another invoice is refused with LINE_NOT_ON_INVOICE rather than silently ignored, and the same line may not appear twice in one request. Omit updateLines to leave the lines untouched.
dutiesAndCustomsAmount requires the entity's Duties and Customs feature to be enabled, and setting it recalculates the invoice's journal entry.
The call runs in one transaction. If any part fails, none of the edits are applied.
Open in the interactive reference
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Api-Version |
header | "v1" |
yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version v1. |
Idempotency-Key |
header | string | no | An opaque caller-chosen string (1-255 characters) that makes this request safe to retry. Repeating the same key with an identical request body replays the original response instead of re-executing - but only once that original request succeeded; a failed attempt re-executes on retry. Repeating the key with a different body is answered with 422. A key still in flight is answered with 409 - as is a key whose original request was interrupted before it finished, for a few minutes afterwards, until that attempt is presumed dead. A completed response stays replayable for 24 hours. The key is scoped to the caller, not to the action: reusing it for a different action is answered with 409 or 422 rather than treated independently. On read actions this header is ignored. On write actions that cannot offer the guarantee it is answered with 400 IDEMPOTENCY_NOT_SUPPORTED rather than silently ignored. |
id |
path | string | yes | The unique identifier for the invoice to update. |
Request body
Required, application/json: updateInvoiceInput.
| Field | Type | Required | Description |
|---|---|---|---|
invoiceDate |
string (date) | no | The date the invoice was issued. Format YYYY-MM-DD. Omit to leave unchanged. Changing it re-derives the due date from the payment term and moves which tax period the invoice falls in. |
paymentTerm |
string | no | The payment term governing when payment falls due, as the term's configured code. Omit to leave unchanged. An empty string is ignored rather than clearing it. This field is write-only: the read endpoints publish the resolved paymentTermDays instead of the term itself. |
customerMessage |
string | no | A free-form message printed on the invoice for the customer. Omit to leave unchanged. It cannot be cleared through this endpoint. An empty string is ignored, not stored. |
purchaseOrderOverride |
string | no | A manually entered PO number that overrides the references derived from the sales order. Omit to leave unchanged. Unlike the other fields here, pass an empty string to clear it and fall back to the sales order's own PO references. |
updateLines |
array of object | no | The line edits to apply, each addressing one existing line of this invoice by its id. Omit to leave the lines untouched. Lines cannot be added or removed here, because the set of lines comes from the sales order's invoice plan. |
updateLines[].id |
string | yes | The unique identifier for the invoice line to edit, as returned by GET accounting/invoices/:id. It must be a line of this invoice, and may appear at most once in the request. |
updateLines[].description |
string | no | The new line description, as shown to the customer. Omit to leave unchanged. |
updateLines[].dutiesAndCustomsAmount |
string (decimal) | no | The duties and customs charged on this line, in the invoice's currency. Requires the entity's Duties and Customs feature to be enabled, and setting it recalculates the invoice's journal entry. Omit to leave unchanged. |
Example:
{
"invoiceDate": "2026-09-05",
"paymentTerm": "<paymentTerm>",
"customerMessage": "Thank you for your business.",
"purchaseOrderOverride": "<purchaseOrderOverride>",
"updateLines": [
{
"id": "5e2a7c81-9d34-4b06-8f19-2c7e4a0d3b58",
"description": "Platform subscription — September 2026",
"dutiesAndCustomsAmount": "45.00"
}
]
}
Response
200 Success
Under data (updateInvoiceOutput):
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | The unique identifier for the updated invoice. Read the invoice back with GET accounting/invoices/:id to see the recalculated totals. |
Response headers
Idempotency-Replayed— Present andtrueonly when this response replays a previously stored one for the same Idempotency-Key, rather than reflecting a live execution. Absent on a live response - never sent asfalse.
Errors
| Code | Status |
|---|---|
INVOICE_NOT_FOUND |
400 |
LINE_NOT_ON_INVOICE |
400 |
DUPLICATE_LINE |
400 |
IDEMPOTENCY_KEY_CONFLICT |
409 |
IDEMPOTENCY_PAYLOAD_MISMATCH |
422 |
Statuses
400— Invalid request or business failure. Codes: INVOICE_NOT_FOUND, LINE_NOT_ON_INVOICE, DUPLICATE_LINE401— Missing or invalid access token403— Not authorized404— Not found409— The Idempotency-Key is still being processed by another request.422— The Idempotency-Key was already used with a different request payload.429— Too many requests500— Internal server error