When to use this endpoint

Use Customers_getExportData only for the Fieldmotion customer CSV exporter. The first request uses _ids=1 to select IDs from filters; later requests send a JSON ID batch plus the chosen field list.

For ordinary integration reads, use Customers_list and Customers_getById; their responses use named fields rather than positional f0, f1 keys.

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
_idsStringYesExact 1 starts the ID-selection phase. Any other value must be a JSON array of IDs for the data phase.
fieldsJSON array stringData phaseRequested field names. Response key f0 corresponds to the first item, f1 to the second, and so on; base id is always included separately.
searchStringNoID phase general substring, applied only when search_fields decodes to a non-empty array.
search_fieldsJSON array stringConditionalGeneral-search fields: all, contact_name, name, notes, street_address_1, street_address_2, account_number, town, county, postcode, landline, mobile, email, or custom-value keys.
idInteger stringNoID phase exact nonzero customer ID.
type_idInteger stringNoExact nonzero customer-type ID.
lead_accInteger stringNoExact nonzero stored lead/account state. Unlike the table endpoint, no grouped meaning is applied.
department_idInteger stringNoExact nonzero department ID.
accountmanager_idInteger stringNoExact nonzero account-manager ID.
is_activeInteger stringNoExact active flag; blank omits the filter and 0 selects inactive rows.
pricebandInteger stringNoPositive price-band ID; -1 selects stored ID 0.
nameStringNoFinds non-deleted name matches, then includes each match and its direct non-deleted children in the export ID set.
notes / county / postcode / landline / mobileStringNoLegacy substring filters. County also searches town; postcode also searches both street lines.
parent_idInteger stringNoExact parent ID when the converted value is greater than -1; 0 selects no parent.
has_sitesInteger stringNoTruthy selects IDs referenced as a parent by a non-deleted customer; zero selects IDs not referenced.
has_jobsInteger stringNoTruthy requires either stored job counter; zero requires both to be zero.
contactName / town / city / street / email / accountNumberStringNoAdditional CRM2 export substring filters. street searches either street line.
countryArrayNoCountry-code values passed to the shared export IN-filter builder. Invalid values can return a builder error.
marketingSourceArrayNoNumeric marketing-source IDs matched against meta.marketing_source through the shared export filter builder.
callbackStatusArrayNoOR-combined callback states -2 overdue, -1 yesterday, 0 today, 1 tomorrow, and 2 future, based on the PHP server date.
dateFromFilter / dateToFilterDate valuesNoWhen both are present and referenceDateField is set, build inclusive date filters with the shared export helper.
referenceDateFieldStringConditionalAllowed values are callback, cdate, or last_edited.
isDateUnixBoolean-likeNoPassed to the shared date-filter helper to interpret supplied date values as Unix values where applicable.

Example request

// Phase 1: select matching IDs.
$selection = FM_api('Customers_getExportData', [
	'_ids' => '1',
	'is_active' => '1',
	'country' => ['IRL'],
]);

// Phase 2: retrieve a retryable ID batch.
$rows = FM_api('Customers_getExportData', [
	'_ids' => json_encode([1042, 1088]),
	'fields' => json_encode(['id', 'name', 'parent_id', 'last_job']),
]);

Example response

// Phase 1
{
  "ids": [1042, 1088]
}

// Phase 2
[
  {
    "id": "1042",
    "f0": "1042",
    "f1": "Northwind Service Centre",
    "f2": "1001",
    "f3": "2026-09-23 15:30:00"
  }
]

Phase-one IDs are emitted as JSON numbers. Phase-two database values are normally strings/null, and each fN position follows the caller’s fields order.

Accepted stored/metadata fields are account_manager, account_number, account_number_sage, accounts_name, accounts_number, appointments_closed, appointments_open, callback, callback_notes, cdate, city, contact_name, country, county, created_by, credit_terms, custom_values, default_nominal, default_taxcode, department_id, email, email_accounting, email_extra, id, industry, is_active, landline, last_edited, last_job, latitude, lead_acc, longitude, meta_default_invoice_due_date, meta_discount, mobile, name, notes, parent_id, postcode, price_band, state, static, street_address1, street_address2, town, type, xero_id, marketing_source, and last_edit_user.

Dynamic fields are custom_values.<key>, last_edited.<path>, and customer_table:<table-id>_<field-id>.

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: _ids"}_ids is absent.
{"error":"_ids should be a JSON array of numbers"}Data-phase _ids is empty, malformed, or does not decode to a non-empty array.
{"error":"fields should be an array of requested field names"}Data-phase fields is absent, malformed, empty, or not an array.
{"error":"unknown field name: ..."}A non-dynamic field is outside the allowlist. Colon-containing names that are not a valid customer_table token are silently skipped instead.
{"ids":[]}The ID-selection query fails or no non-deleted customer matches. A general search with missing/invalid search_fields also returns this response.
[]A valid data-phase ID array matches no customer rows.

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

Behaviour and edge cases

  • Phase one always adds deleted=0. Phase two does not: an explicitly supplied ID can export a soft-deleted or inactive customer. Phase two also does not verify that IDs came from phase one.
  • All phase-one filters are AND-combined except the values within country, marketing-source, and callback-status groups. Neither phase establishes a stable row order.
  • IDs and fields are integer-converted/allowlisted before the data query. Duplicate IDs collapse in SQL; duplicate field requests produce multiple fN values.
  • last_job uses the maximum stored job end epoch for matching numeric customer_id and converts it to tenant-local time. The derived query does not filter soft-deleted jobs or constrain customer type.
  • xero_id uses only Xero customer links for the current xero_token.tenantId and formats the stored 32-character remote value as a hyphenated GUID.
  • default_nominal, default_taxcode, and marketing_source translate stored IDs to current display strings; missing references become blank.
  • last_edit_user returns the user ID from the newest customer-change row. customer_table fields return a JSON-encoded array of all matching row values, or a single-space string when no value exists.
  • custom_values and other stored JSON values remain encoded strings. static is always blank.
  • The handler streams both phases directly with invalid UTF-8 substitution and provides no built-in page size. The UI is responsible for sending retryable ID batches.

See it in Fieldmotion

CRM1

On Customers, pass the export-password dialog and configure a CSV export. The export widget first calls Customers_getExportData with _ids=1 and the current CRM1 table filters, then requests selected fields in ID batches.

CRM2

On Customers, choose Export. CRM2 first gathers filtered IDs through Customers_getDataTable, then its export widget calls Customers_getExportData in data phase for selected fields. It does not use this endpoint’s phase-one filters in that path.

Related endpoints