Contracts
Build the CRM1 contracts table
/a/Contracts_getDT
Build CRM1’s paged Contracts table with legacy positional rows, status/date/customer filters, linked-job costs, stock, vehicles, and file counts.
When to use this endpoint
Use Contracts_getDT only when reproducing CRM1’s Contracts page. Its filters, column numbers, and 21-position rows are coupled to that screen.
For CRM2-style named fields use Contracts_getDataTable; for a small selector use Contracts_list.
Authentication and permissions
The request must authenticate with signed API-key fields or a logged-in CRM session. The handler performs no contract-page permission or feature-setting check.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
draw | Integer string | No | DataTables counter, integer-converted and echoed; defaults to 0. |
start | Integer string | No | Zero-based SQL offset; defaults to 0. |
length | Integer string | No | Page size; defaults to 10. Zero and negative values are not rejected before SQL. |
active | Integer string | No | Exact stored status after integer conversion. Omission becomes 0, so this endpoint defaults to completed contracts rather than all or active contracts. |
order[0][column] | Integer string | No | Sort column: 0 ID, 1 name, 2 number, 3 type, 7 budget, 14 creation date, 16 start date, 17 expiry date, or 18 completion date. Other values use name. |
order[0][dir] | String | No | Exact desc selects descending; every other value selects ascending. |
dateFrom / dateTo | Date strings | No | Inclusive expiry-date range. The range is applied only when both keys are present; values are not date-validated. |
nonExpiring | Integer string | No | With both date bounds, exact 1 also includes null expiry and legacy zero-date values. |
name / number / notes | Strings | No | Independent substring filters. Name is lowercased on both sides; number and notes use the database collation. Presence matters, so a blank value adds a match-all condition. |
customer_name | String | No | Finds non-deleted customers by lowercased name substring, then searches the contract’s cached relationship text for their IDs. It does not search asset names or distinguish relationship type. |
type | Integer string | No | Positive contract-type ID. Zero/blank does not filter. |
search[value] | String | No | Trimmed name substring. Numeric input additionally matches the exact contract ID. |
Example request
$table = FM_api('Contracts_getDT', [
'draw' => '5',
'start' => '0',
'length' => '25',
'active' => '1',
'customer_name' => 'northwind',
'order' => [['column' => '1', 'dir' => 'asc']],
]);
Example response
{
"draw": 5,
"recordsTotal": "48",
"recordsFiltered": "1",
"data": [
[
720, "North Region Service Contract", "CT-720", "3", "[8801,8802]",
"[[0,1042]]", "Priority cover", "25000",
[325.5, 90, 1200, 180, 16, 240, 65],
4200, 5166, "", "", "2026-01-10 09:30:00", "1", "2026-12-31",
[[[12,2]]], [["4","80"]], null, 2, "2026-01-15"
]
]
}
Row positions are: ID, name, number, type ID, JSON job-ID array, cached customer/asset JSON text, notes, budget, [stock cost, mileage cost, labour cost, miles, hours, schedule-of-rates cost, miscellaneous cost], net, gross, two empty placeholders, creation date, active value, expiry date, nested decoded stock-use arrays, [vehicle ID, miles] arrays, completion date, non-deleted contract-file count, and start date.
Database scalar values generally remain strings. Contract IDs and linked job IDs are integer-converted; calculated costs can be numeric.
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. |
Authentication error | No valid API signature or logged-in CRM session is available. |
Empty <code>data</code> with normal counts | The requested page/filter has no matching non-deleted contract. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
recordsTotalcounts every non-deleted contract regardless of status.recordsFilteredincludes the mandatory status and all supplied filters.- Job IDs are the unique union of type-6 legacy relationship rows and non-deleted jobs whose direct
contract_idmatches. Costs use that union and include incomplete jobs; schedule-of-rates values are recalculated when necessary. - Stock and vehicle details come only from non-deleted jobs with a direct
contract_id. Thus the job list/costs and detail arrays can represent different sets. - The customer-name filter searches a cached JSON-like text value for
,ID]. Equal customer/asset numeric IDs can collide, and stale cache content can affect filtering before a returned row is rebuilt.
Side effects
- If a returned contract’s metadata contains
customersDirty, the endpoint rebuilds its customer/asset cache, relationship rows, metadata, andlast_editedwhile serving this read request.
See it in Fieldmotion
CRM1
Open Contracts. Status/date/type/customer filters, search, sorting, and paging call Contracts_getDT.
CRM2
A production-source search found no CRM2 caller. CRM2’s Contracts list and Kanban use Contracts_getDataTable.
Related endpoints
Contracts_getDataTableis CRM2’s named-field table route.Contracts_getExportDataimplements CRM1’s export flow.