Invoices
List invoice rows
/a/InvoiceRow_list
List active editable invoice rows with stable row IDs, optionally restricted to one directly linked job.
When to use this endpoint
Call this before targeted row add/edit/delete workflows. It establishes table-backed storage for legacy invoices and gives the editor stable IDs and positions.
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. |
job_id | Positive integer-compatible | No | When positive, returns rows owned by that job. Unassigned legacy rows count as belonging to the job only when the invoice has exactly one direct/legacy linked job. The supplied job itself is not validated as linked. |
Example request
$result = FM_api('InvoiceRow_list', ['invoice_id' => 981, 'job_id' => 2204]);
Example response
{
"ok": 1,
"invoice_id": 981,
"rows": [{"description":"Service","qty":2,"price":50,"net":100,"gross":120,"job_id":2204,"invoice_row_id":441,"position":0}]
}
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 does not exist"} | The invoice is absent or soft-deleted. |
{"error":"invoice row table unavailable"} | The tenant has not received the required invoice-row schema migration. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Rows are ordered by stored position then row ID. There is no pagination. Empty invoices return
rows: []. - A multi-job invoice excludes unassigned rows from every job-filtered response; the unfiltered response retains them.
- Tax and nominal aliases are normalized in returned rows. Database scalar types inside row JSON follow the normalized stored values rather than a fixed all-string contract.
Side effects
- May lazily create table-backed rows and set the invoice storage marker under the invoice-row lock. Subsequent reads are side-effect free.
See it in Fieldmotion
CRM1
Job Invoice, invoice table widgets, and the main Invoices editor call this route before rendering persisted line items.
CRM2
Configurable invoice and Job Costs widgets load rows through this endpoint and retain invoice_row_id for targeted saves.
Related endpoints
InvoiceRow_listsupplies stable row IDs and positions before a targeted edit.Invoice_setRowsreplaces the complete row collection for compatibility callers.