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

ParameterTypeRequiredDescription
drawInteger stringYesDataTables request counter, integer-converted and echoed in the response. Presence is required; blank becomes 0.
startInteger stringNoZero-based SQL offset; defaults to 0. Negative values are not rejected before reaching SQL.
lengthInteger stringYesPage size after integer conversion; must be greater than zero.
order[0][column]Integer stringNoColumn 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]StringNoExact asc selects ascending for a recognized column; every other value selects descending. The fallback is always name ascending.
fIdInteger stringNoExact customer ID when it converts to a nonzero integer.
dateFromDate/time stringNoInclusive lower bound on customer creation time (cdate). No format validation is performed.
dateToDate/time stringNoEnables the legacy creation-date upper-bound branch, but that branch mistakenly uses dateFrom plus 23:59:59 instead of this value.
fNameStringNoSubstring 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.
fNotesStringNoCustomer notes substring.
fIndustryStringNoCustomer industry substring.
fCountyStringNoNormally searches county and town. A leading quote also searches country; !<country-name> resolves the display name to a stored country code.
fTownStringNoTown substring.
fPostcodeStringNoSubstring across postcode and first street line; an optional leading quote is merely removed.
fEmailStringNoCase-insensitive email substring.
fLandlineStringNoLandline substring; an optional leading quote is removed.
fMobileStringNoMobile substring; an optional leading quote is removed.
fTypeInteger stringNoExact nonzero customer-type ID.
fDepartmentInteger stringNoExact nonzero department ID.
fLeadAccInteger stringNoLegacy 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.
fCallbackInteger stringNo-2 overdue, -1 yesterday, 0 today/next 24 hours, 1 tomorrow, or 2 future. Presence matters, so the string 0 applies today.
fApptsInteger stringNoObsolete 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.
fHasJobsInteger stringNoWhen fAppts is not active, truthy selects any nonzero open/closed job counters and zero selects both counters equal to zero.
fAccountManagerInteger stringNoExact account-manager ID. The magic value -1 selects stored ID 0.
fActiveInteger stringNoExact active flag; blank omits the filter, while 0 selects inactive customers.
fParentInteger stringNo-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.
fIncludeInteger stringNoWith a positive fParent, 2 means parent only; other values mean direct children.
fPriceBandInteger stringNoPositive values select that price-band ID; -1 selects stored ID 0.
fHasSitesInteger stringNoTruthy 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]StringNoGeneral case-insensitive substring. It is applied only when search[fields] decodes to a non-empty array.
search[fields]JSON array stringConditionalFields 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

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":"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 0A 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 fActive filters them.
  • recordsTotal is the tenant-wide non-deleted customer count. recordsFiltered applies 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 login value 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 fCounty and fPostcode branches build ungrouped SQL OR terms. When combined with other filters, SQL operator precedence can allow a country/town/street match to bypass preceding AND conditions.
  • 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