When to use this endpoint

Use for the CRM2 Quotes table or Kanban query. This contract differs from CRM1’s positional getDT rows.

Authentication and permissions

Authenticate with signed API-key fields or a CRM session. Requires Quotes View (pageQuotes_view); non-admin users blocked by legacy crm_access bit 32 are denied. Client administrators inherit page permissions.

Quote visibility follows the account’s department/account-manager customer filters for non-admin users, including signed keys. Export routes additionally require pageMain_exportTableData. Linked Jobs require Jobs View and their TeamAccess scope; invoice enrichment requires Invoices View and the legacy invoice access check.

Parameters

ParameterTypeRequiredDescription
fieldsNative array of mapped namesNoDefaults to id and hasJobs because the handler adds these names before querying. Supply a native array for other fields; JSON text is rejected by validation. Unknown names are ignored. See mapped fields below.
start / length / drawInteger-compatible table controlsNoDefaults 0 / 10 / 0; offsets and sizes are not bounded. Used when isTable is nonzero/default.
isTable / limitInteger-compatible switchesNoisTable=0 disables table paging/counts; positive limit caps that mode, otherwise all matches are returned. Default isTable=1.
orderBy / orderDescMapped name and directionTogetherMapped field and validated asc/desc direction. ID is a stable tie-breaker.
orderNative DataTables order arrayNoFallback uses first column index minus one to choose the requested mapped field, and exact desc or asc. A name/direction pair is clearer.
Mapped filtersScalars, native lists or picker objectsNoMapped text scalars use contains; text arrays use exact IN, numeric scalars integer-convert and numeric arrays use numeric IN. customer/user pickers accept {id} objects or lists; malformed pickers fail.
searchField / searchValueMapped field name(s) and textNoGeneral contains search over selected fields or All. Exact searchField=status has special case-insensitive name-prefix matching; missing matches can emit a warning.
jobId / appointmentIdLegacy string filter for Job IDNoCanonical jobId or legacy appointmentId alias. Validated ID text adds an active permitted Job relation substring filter.
invoices / ordersString ID/reference fragmentsNoValidated fragments. Includes direct and permitted active Job-linked invoices (types 3/4), and active requisition/purchase orders targeting the quote.
metaEmailSentNative list of 0/1 choicesNoNative 0/1 list. Single 0 matches missing/not-sent markers within a parenthesized predicate; both choices disable the filter.
requestSignatureNative list of statusesNoNative list containing only 0/1 request statuses; EXISTS filtering avoids duplicated quotes. Expired request history remains visible.
hasFilesNative list of choicesNoCRM2’s verified choices: [0] Has File, [1] Has No File, both disable filtering. Deleted files do not count.
customer / childJobAndAssetPicker value / native expansion listNoWhen customer is supplied, expansion choice 0 adds immediate child customer IDs. No asset expansion is implemented in this handler.
recurringIDPositive recurrence IDNoFilters generated occurrences for an accessible rule; requires recurringQuotes feature and Quotes View. Select recurringID in fields for response markers.
referenceDate / dateFrom / dateToMapped date alias / integer day offsetsNoValid referenceDate enables an inclusive range from account-local today plus dateFrom to today plus dateTo end-of-day. Date-only fields use date boundaries. Defaults are not an implicit filter.
offsetFrom / offsetToNative {hour,minute} objectsNoAdjust reference date bounds: hour is negated and minute added. No validation of ranges.
timeRangeFrom / timeRangeToInteger hoursNoHour-of-day filtering requires timeRangeFrom to be present; a to-only request does not activate the branch. Uses tenant timezone (Europe/London fallback for this filter).
groupBy / advanceSearchNative arraysNoMapped advanced filters are validated; groupBy and raw SQL clauses are rejected.

Example request

$table = FM_api('Quotes_getDataTable', [
	'fields'=>['id','quoteNum','customer','totalGross'],
	'start'=>0,'length'=>20,'orderBy'=>'id','orderDesc'=>'desc',
]);

Example response

{"data":[{"id":"1042","quoteNum":"QT-1042","customer":{"id":"1088"},"totalGross":"120.00","hasJobs":"0","jobIDs":[],"orders":[],"requestSignature":[],"invoices":[]}],"draw":0,"recordsTotal":"1","recordsFiltered":"1"}

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":"error in database query"}The main mapped data SELECT fails.
{"error":"invalid picker filter: customer"}Malformed mapped customer picker; other picker keys use the same pattern.
{"error":"Recurring Quotations are not enabled for this account"}recurringID filter supplied without the feature.
{"error":"permission denied"}Required Quotes/Export permission is absent or legacy access restrictions apply.

Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.

Behaviour and edge cases

  • fields defaults to id/hasJobs and otherwise must be a native mapped-name list. Active quote/customer visibility is applied before paging, including signed keys. Both recordsTotal and recordsFiltered respect that visibility.
  • Validates directions, native selectors, picker objects, date/hour controls and mapped advanced filters. Rejects raw SQL clauses, malformed structures and groupBy; legacy quote_ advanced IDs are normalized. Tied table rows use a stable ID order.
  • Job, invoice, order and signature filters use EXISTS/subqueries rather than duplicate-producing joins. Numeric/name fragments are validated and escaped before SQL. Email-not-sent includes missing markers in a parenthesized predicate, so it cannot bypass other filters.
  • The verified CRM2 file-choice contract is preserved: hasFiles=[0] means Has File, [1] means Has No File, and both choices remove the filter. Only non-deleted type-Quote files count.
  • Always adds id, hasJobs, jobIDs, orders, requestSignature and invoices. Job IDs/counts use current distinct active permitted Jobs rather than stale cache. Related orders exclude deleted rows; invoices require invoice access and combine direct/type-3/4 links through active permitted Jobs.
  • jobId is the canonical Job filter; appointmentId remains a compatible legacy alias. requestSignature selects request status, without hiding expired history. Recurrence filtering still requires the feature and an accessible rule.
  • isTable=0 returns data without table counts and uses positive limit when supplied; otherwise all matching rows are returned. Default table paging is start=0,length=10.
  • No direct caller for this endpoint was found in the mobile app or its m-service intermediary.

Side effects

  • Reads active permitted records without quote cost, history, email or derived Job-cache writes.

See it in Fieldmotion

CRM1

No direct caller found. CRM1’s Quotes screen uses Quotes_getDT.

CRM2

Quotes table and Kanban load through Quotes_getDataTable. CRM2 export first obtains matching IDs with fields:[id], isTable:0, then sends batches to an exporter.

Related endpoints