Customers
Query the CRM1 Customers table
/a/Customers_getDT
Build the legacy CRM1 Customers table with server-side filtering, sorting, paging, relationship context, and compact positional rows.
When to use this endpoint
Use Customers_getDT only when reproducing CRM1’s Customers page. Its parameters and 17-position row arrays are coupled to that table’s columns and filters.
For a new integration use Customers_list; for CRM2’s mapped object rows use Customers_getDataTable.
Authentication and permissions
The request must authenticate with signed API-key fields or a logged-in CRM session. The handler performs no additional page or role-permission check.
The lookup and any write use the authenticated tenant; an ID from another tenant cannot be addressed through this call.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
draw | Integer string | Yes | DataTables request counter, integer-converted and echoed in the response. Presence is required; blank becomes 0. |
start | Integer string | No | Zero-based SQL offset; defaults to 0. Negative values are not rejected before reaching SQL. |
length | Integer string | Yes | Page size after integer conversion; must be greater than zero. |
order[0][column] | Integer string | No | Column index: 0 ID, 1 flagged, 2 name, 4 county, 5 postcode, 6 landline, 7 mobile, 8 type, 9 lead/account state, 10 callback, 11 account manager, 12 closed-job count, or 13 login. Other indexes fall back to name. |
order[0][dir] | String | No | Exact asc selects ascending for a recognized column; every other value selects descending. The fallback is always name ascending. |
fId | Integer string | No | Exact customer ID when it converts to a nonzero integer. |
dateFrom | Date/time string | No | Inclusive lower bound on customer creation time (cdate). No format validation is performed. |
dateTo | Date/time string | No | Enables the legacy creation-date upper-bound branch, but that branch mistakenly uses dateFrom plus 23:59:59 instead of this value. |
fName | String | No | Substring search across customer/parent names and contact names. in:<id> selects that non-deleted customer plus its direct non-deleted children. A leading quote is stripped but does not make the match exact. |
fNotes | String | No | Customer notes substring. |
fIndustry | String | No | Customer industry substring. |
fCounty | String | No | Normally searches county and town. A leading quote also searches country; !<country-name> resolves the display name to a stored country code. |
fTown | String | No | Town substring. |
fPostcode | String | No | Substring across postcode and first street line; an optional leading quote is merely removed. |
fEmail | String | No | Case-insensitive email substring. |
fLandline | String | No | Landline substring; an optional leading quote is removed. |
fMobile | String | No | Mobile substring; an optional leading quote is removed. |
fType | Integer string | No | Exact nonzero customer-type ID. |
fDepartment | Integer string | No | Exact nonzero department ID. |
fLeadAcc | Integer string | No | Legacy state selector: 1/2 accept lead states 0–2/null, 4 accepts account states 3–4, 3 means state 4 with open jobs, and other nonzero values match directly. |
fCallback | Integer string | No | -2 overdue, -1 yesterday, 0 today/next 24 hours, 1 tomorrow, or 2 future. Presence matters, so the string 0 applies today. |
fAppts | Integer string | No | Obsolete wire name for minimum closed-job count. Values greater than zero require the stored count to be at least this value and take precedence over fHasJobs. |
fHasJobs | Integer string | No | When fAppts is not active, truthy selects any nonzero open/closed job counters and zero selects both counters equal to zero. |
fAccountManager | Integer string | No | Exact account-manager ID. The magic value -1 selects stored ID 0. |
fActive | Integer string | No | Exact active flag; blank omits the filter, while 0 selects inactive customers. |
fParent | Integer string | No | -1 means all. Otherwise selects direct children of this parent, except a positive ID with fInclude=2 selects the parent itself. 0 selects customers with no parent. |
fInclude | Integer string | No | With a positive fParent, 2 means parent only; other values mean direct children. |
fPriceBand | Integer string | No | Positive values select that price-band ID; -1 selects stored ID 0. |
fHasSites | Integer string | No | Truthy selects customer IDs referenced as a parent; zero selects IDs not in that set. The preliminary parent-ID query includes only non-deleted child rows. |
search[value] | String | No | General case-insensitive substring. It is applied only when search[fields] decodes to a non-empty array. |
search[fields] | JSON array string | Conditional | Fields for general search: all, contact_name, name, parent_name, parent_contact_name, notes, street_address_1, street_address_2, account_number, town, county, postcode, landline, mobile, email, or custom-value keys. |
Example request
$table = FM_api('Customers_getDT', [
'draw' => '4',
'start' => '0',
'length' => '25',
'fActive' => '1',
'fHasJobs' => '1',
'search' => [
'value' => 'northwind',
'fields' => json_encode(['name', 'account_number']),
],
'order' => [['column' => '2', 'dir' => 'asc']],
]);
Example response
{
"data": [
[
1, 0, "Northwind Cork|Sam Example", "1",
["IRL", "Cork", "Cork"],
["T12 A3BC", "51.8985", "-8.4756", "14 Harbour Road"],
"+353215550100", "+353875550100", ["2", "7"],
["4:1:Account (1 open)", {"id":"3","name":"Standard"}],
["2026-09-26 10:30", "Renewal call"], "18", "4", "",
["1088", "1001"], [], "21,25"
]
],
"draw": 4,
"recordsTotal": "250",
"recordsFiltered": "1"
}
Each row position is: active flag, flagged flag, name|contact_name, notes-present flag, [country, county, town], [postcode, latitude, longitude, street_address1], landline, mobile, [type, department_id], [lead/account summary, price-band row-or-0], [callback without seconds, callback_notes], account-manager ID, stored appointments_closed job count, login token, customer-to-root ancestor IDs, an always-empty error list, and the stored files value.
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":"missing or invalid parameter: draw"} | draw is absent. |
{"error":"missing or invalid parameter: length"} | length is absent, blank, zero, or negative after integer conversion. |
Empty DataTables result with both counts 0 | A general search[value] is supplied without a valid non-empty search[fields] array; the handler returns before running count queries. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Soft-deleted customers are excluded from rows and both counts. Inactive customers remain unless
fActivefilters them. recordsTotalis the tenant-wide non-deleted customer count.recordsFilteredapplies the complete filter set before page offset/length.- Default ordering is customer name ascending. A recognized requested column uses the requested direction; there is no stable secondary sort for ties.
- Parent ancestry is followed one database lookup at a time and stops at a missing/deleted parent or a detected cycle. The row’s own ID is always first.
- Callback comparisons use the PHP server’s current date/time. The handler does not explicitly switch to the tenant timezone.
- The fixed row always includes the stored customer
loginvalue at position 13. The handler has no field-level permission check, so consumers must treat that legacy value as sensitive and avoid exposing it. - The leading-quote
fCountyandfPostcodebranches build ungrouped SQLORterms. When combined with other filters, SQL operator precedence can allow a country/town/street match to bypass precedingANDconditions. - The endpoint raises its execution limit to 30 seconds and performs extra per-page queries for price bands and ancestry.
See it in Fieldmotion
CRM1
Open Customers. Searching, changing column filters, sorting, or paging reloads Customers_getDT; CRM1 sends the DataTables fields plus its f* filters.
CRM2
A production-source search found no CRM2 caller. CRM2’s Customers page uses Customers_getDataTable.
Related endpoints
Customers_getDataTableis CRM2’s mapped customer table endpoint.Customers_getExportDataimplements the legacy two-stage CSV export.Customers_listis the simpler integration-oriented list endpoint.