Invoices
Delete one invoice row
/a/InvoiceRow_delete
Soft-delete one persisted invoice row and recalculate invoice and linked-job totals.
When to use this endpoint
Use a positive row ID returned by InvoiceRow_list. Position lookup exists only for legacy callers that do not yet retain row IDs.
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
| Parameter | Type | Required | Description |
|---|---|---|---|
invoice_id / id | Positive integer-compatible | Yes | Active invoice ID. |
row_id / invoice_row_id | Positive integer-compatible | Normally | Active row-table ID scoped to this invoice. |
position | Integer-compatible | If no row ID | Legacy zero-based position lookup. Negative/missing position with no row ID is rejected. |
Example request
$result = FM_api('InvoiceRow_delete', ['invoice_id' => 981, 'row_id' => 441]);
Example response
{
"ok": 1,
"total_net": 50,
"total": 60,
"row_id": 441
}
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs. |
{"error":"invoice row does not exist"} | A positive row ID is absent, deleted, or belongs to another invoice. |
{"error":"cannot edit invoices that are marked Paid"} | Invoice status is Paid. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- If legacy position lookup finds no row, the route returns
{"ok":1,"warning":"invoice row did not exist","row_id":0}; a missing positive row ID instead returns an error. - Surviving row positions are not compacted after deletion. List ordering remains position then row ID.
Side effects
- Sets row
deleted=1with deletion/edit timestamps, recalculates invoice totals/edit metadata, firesInvoice_edit, and updates linked-job totals including the former owning job. It does not write the tenant object-deletion stream.
See it in Fieldmotion
CRM1
Job Invoice, the invoice table widget, and the main Invoices editor delete persisted rows through this route.
CRM2
Configurable invoice and Job Costs table widgets call it with a positive row ID.
Related endpoints
InvoiceRow_listsupplies stable row IDs and positions before a targeted edit.Invoice_setRowsreplaces the complete row collection for compatibility callers.