When to use this endpoint

Use Customer_stockGetExportData through the CRM export widget. Phase one sends the sentinel _ids=1 to build an ID list from legacy customer filters; phase two sends a JSON ID array and JSON field list to retrieve export rows.

CRM2 already has job IDs from its newer table query and normally enters at phase two.

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
_idsString or JSON array stringYesExact string 1 selects phase one. Any other value must decode to a nonempty JSON array for phase two.
customer_idInteger stringPhase onePositive target ID used in phase one. Despite the name, the target kind is controlled by customer_type. Existence is not checked.
customer_typeInteger stringNoPhase-one job target type; defaults to 0 (customer). 1 represents an asset and 2 a location in the meeting target model.
dateFromDate/time stringNoPhase-one inclusive lower bound on stored date_completed. When present, dateTo is also applied.
dateToDate stringNoPhase-one inclusive upper date through 23:59:59; defaults to the server’s current date when dateFrom is present.
daysFromInteger stringNoPhase-one relative lower day using the PHP server’s current date inside SQL. When present, daysTo is also used.
daysToInteger stringNoPhase-one relative upper day; defaults to 0, with the next midnight exclusive.
idInteger stringNoPhase-one exact job ID. Zero and blank do not filter.
usernameStringNoPhase-one assigned-user name substring. No matching user forces an empty ID list.
userListForm arrayNoPhase-one list of assigned user IDs. Used only when a nonempty array is supplied.
fieldsJSON array stringPhase twoOne or more exact names: id, date_completed, stock_used, or user_id|user_type. Unknown fields reject the complete request.

Example request

// Phase 1
$selection = FM_api('Customer_stockGetExportData', [
	'_ids' => '1',
	'customer_id' => '1088',
	'customer_type' => '0',
	'dateFrom' => '2026-09-01',
	'dateTo' => '2026-09-30',
]);

// Phase 2
$rows = FM_api('Customer_stockGetExportData', [
	'_ids' => json_encode(['7204', '7219']),
	'fields' => json_encode(['id', 'date_completed', 'stock_used']),
]);

Example response

// Phase 1
{"ids":["7204","7219"]}

// Phase 2
[
  {"id":"7204","f0":"7204","f1":"2026-09-24 11:00:00","f2":"[{\"name\":\"Filter\",\"code\":\"FLT-1\",\"categories\":\"[]\",\"quantity\":\"2\"}]"}
]

Phase-two aliases follow requested order: f0, f1, and so on, while a separate id is always present. user_id|user_type creates suffixed aliases such as f3_0 and f3_1.

stock_used is transformed into an encoded JSON array containing each current stock row’s name, code, categories, and the recorded quantity. Missing/deleted stock IDs are not explicitly normalized.

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":"missing or invalid parameter: customer_id"}Phase one receives no positive customer_id.
{"error":"_ids should be a JSON array of numbers"}A phase-two _ids value does not decode to a nonempty array.
{"error":"fields should be an array of requested field names"}fields is absent, empty, or not a JSON array.
{"error":"unknown field name: name"}A requested field is outside the four-name allowlist; name is replaced by that submitted value.

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 selects non-deleted jobs whose completion state is not NULL, including state 0, and whose main stock_used text is non-NULL and contains id. It does not include stock found only in subforms.
  • Phase-one IDs are ordered ascending by job ID and are not paginated. The endpoint reads no stock or active filter even though CRM1 includes both in its export-widget parameters.
  • Phase two integer-casts every submitted ID. It does not guarantee output order matches input order because the query has no ORDER BY.
  • The date_completed compatibility branch checks an is_complete value that is not selected by the allowlist, so the requested date is returned as stored rather than blanked for incomplete jobs.
  • The combined user field exposes the legacy underlying aliases; its attempted outsourced-user substitution depends on metadata that this endpoint does not select.

See it in Fieldmotion

CRM1

On a customer’s Stock Used tab, select Export. The export widget first calls Customer_stockGetExportData with _ids=1 and the page filters, then calls it again in chunks with JSON IDs and selected fields. CRM1 shows the button only when permission bit 256 is not set; the endpoint has no matching export-permission check.

CRM2

On CRM2 Customer Stock or Asset Stock, select export and filter Network requests for Customer_stockGetExportData. CRM2 collects IDs using CustomersStock_getDataTable and the export widget sends those IDs into this endpoint’s retrieval phase.

Related endpoints