When to use this endpoint

Use this compatibility route for whole-list replacement. Prefer InvoiceRow_* endpoints for targeted table-backed row edits.

Authentication and permissions

The request must use a logged-in CRM session or valid signed API credentials and is scoped to that tenant.

Users whose legacy crm_access mask contains bit 64 receive {"error":"no permission to access api"}. No record-owner check is made.

Parameters

ParameterTypeRequiredDescription
idPositive integerYesActive invoice ID.
rowsJSON array stringYesComplete replacement row list. Empty row structures are normalized out; row nominal ID/code conflicts are rejected.

Example request

$result = FM_api('Invoice_setRows', [
	'id' => 981,
	'rows' => json_encode([['description' => 'Service', 'qty' => 1, 'price' => 100, 'taxpc' => 20]]),
]);

Example response

{
  "ok": 1
}

Errors and unusual responses

ResponseCondition
{"error":"not logged in"}No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs.
{"error":"invalid parameter: rows"}The value is not a JSON array.
{"error":"cannot edit invoices that are marked Paid"}The invoice is Paid.
{"error":"...refer to different accounts..."}A line supplies conflicting nominal identifiers.

Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.

Behaviour and edge cases

  • The replacement runs under an invoice row lock, making concurrent whole-list saves serialize. Identical normalized rows return warning: no change necessary.
  • Storage may migrate to invoices_rows while the legacy JSON cache remains compatible.

Side effects

  • Replaces rows, recalculates net/gross totals and linked-job price totals, advances edit metadata, and fires Invoice_edit.

See it in Fieldmotion

CRM1

No current direct CRM1 string caller was found; legacy integrations and regression tests use this compatibility route.

CRM2

No current direct production CRM2 caller was found; mapped saves use Invoice_updateData and targeted edits can use InvoiceRow_*.

Related endpoints