Customers
Update a mapped customer
/a/Customer_updateData
Update one customer through the CRM2 field-map/layout pipeline.
When to use this endpoint
Use Customer_updateData for saves from the configurable CRM2 customer layout and for integrations that deliberately adopt its camel-case map.
Use Customer_edit only for the separate CRM1 snake-case contract. The response and validation behavior are not interchangeable.
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 |
|---|---|---|---|
id | Integer string | Yes | One non-deleted customer ID. The shared helper can technically receive an array, but this wrapper’s history, notification, and event code assumes a scalar; arrays are unsupported. |
name | String | No | Maximum 178 bytes. If another active customer has the same case-insensitive name, this one field is silently removed from the update while other fields continue. |
accountNumber, contactName, email, landline, mobile | Strings | No | Mapped identity/contact fields with limits 58, 82, 64, 38, and 40 bytes. Blank contactName is rejected because the map marks it required when supplied. Email syntax is not checked. |
industry, notes, creditTerms, accountsName, accountsNumber | Strings | No | Other direct mapped text fields. Only the wrapper’s listed length-limited fields are checked before the generic conversion. |
streetAddress1, streetAddress2, town, city, county, state, postcode, country | Strings | No | Mapped address fields. Limits: town/city 40, county 299, state 255, postcode 20. Country accepts a known name, alpha-2 code, any three-character value, or Northern Ireland and stores uppercase alpha-3 where resolvable. |
latitude / longitude | Numbers | No | Coordinate handling runs only when both are supplied. By default the merged current/request address is geocoded; use flagIsSetLocation=true to trust and store submitted floats. |
flagIsSetLocation | String | No | Only a value comparing to literal true selects manual-coordinate mode; it is removed before mapped storage. |
parentId / parent, accountManagerID / accountManager | Integer or picker object | No | Mapped parent and account-manager IDs. Picker objects are flattened through their id member. |
departmentId, areaID, type, priceBand, billing_target | Integers | No | Mapped relationship/configuration fields. Referenced IDs are not validated by the generic update helper. |
isActive | Integer/boolean-like | No | Mapped activity state. A value converting to zero also disables all active customer recurrences and removes their future incomplete jobs through the recurrence workflow. |
is_active | Internal snake-case alias | No | Not in the field map, so it does not change the customer row; nevertheless zero still triggers recurrence deactivation. Do not use this legacy alias. |
callback, callbackNotes, customValues, contacts, widgetTableContact | Mapped value | No | Callback/contact structures. Widget contact rows are converted to stored contacts keys; customValues is a complete JSON value. |
marketingSource, accountSage, discount, doNotSMS, defaultNominal, defaultTaxcode | Mapped scalar | No | Allow-listed values stored under customer meta. |
accountingEmail, additionalEmail, additionalAccountingEmail, doNotEmailInvoices, owned, defaultInvoiceFormID | Mapped scalar | No | Additional allow-listed metadata values. Picker defaultInvoiceForm can supply defaultInvoiceFormID. |
defaultInvoiceDueDateMode | String | No | Blank or one of days_after_invoice_date, days_after_invoice_month_end, day_of_invoice_month, and day_of_following_month. |
defaultInvoiceDueDate | Integer string or blank | No | 0–3650, restricted to 1–31 for day-of-month modes. Blank removes the metadata key. |
default_invoice_due_date_mode / default_invoice_due_date | Legacy validation aliases | No | The wrapper validates these snake-case names but the field map does not store them. Use the camel-case names above. |
login, password, passwordSalt, meta, changes, editedUuid, appId, lastEdited, lastEditedAll, files, createdBy, createDate, leadAcc, hasInvoices | Mapped internal scalar | No | Hidden/internal map keys currently accepted by the generic helper. They are not a supported integration contract and should not be submitted. |
appointmentsOpen, appointmentsClosed | Integer | No | Obsolete hidden job-count storage identifiers accepted by the shared map. Do not update them directly. |
noRecord / noRecordCustom | Arrays | No | Internal controls that mark selected generic activity-log entries hidden. |
Example request
$result = FM_api('Customer_updateData', [
'id' => '1042',
'name' => 'Northwind Service Centre',
'country' => 'United Kingdom',
'defaultInvoiceDueDateMode' => 'days_after_invoice_date',
'defaultInvoiceDueDate' => '30',
]);
Example response
{
"ok": 1
}
The wrapper discards the generic helper’s oldData and always returns only ok after a non-error result. A read-back is required to prove which fields changed.
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: id"} | id is absent. A supplied unknown ID instead becomes a swallowed warning; see edge cases. |
{"error":"That Contact Number is already in use."} | The uniqueness setting is enabled and another active customer has the exact trimmed contact number. |
{"error":"<field> has a maximum length of <n>"} | A wrapper-validated text field exceeds its byte limit. |
{"error":"unknown country: <VALUE>"} | A supplied nonblank country cannot be normalized. |
{"error":"invalid default invoice due date mode"} | The mapped or legacy mode alias is invalid. |
{"error":"default invoice due date value must be between ..."} | The due-date value is invalid for the selected mode. |
{"error":"missing or invalid parameter: contactName"} | A supplied contactName is blank. |
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 by the generic update. Unknown parameters are ignored unless the wrapper gives them special behavior.
- The
customer-landline-uniquesetting checks exact text among other active rows. This route does not enforcecustomers-require-landlines. - When both coordinates are supplied and manual mode is false, a geocoding hit replaces them. A miss preserves the old stored coordinates rather than accepting the supplied point.
- Changing to a duplicate name is silently skipped. The response does not disclose that skip.
- There is no pagination and the update is not transactional with history, recurrence, notice, notification, cache-refresh, or event side effects.
Side effects
- Writes generic activity logs and customer change-history rows for changed mapped fields; large values can be replaced by bounded audit placeholders.
- Maintains address/parent history and resets cached job addresses for an existing customer after a non-error helper result.
- An activity value of zero deactivates customer recurrences and their future incomplete jobs.
- Sends mention notices, publishes an update notification, and fires
Customer_edit, including on some no-op or missing-row paths. - May call external geocoding services.
See it in Fieldmotion
CRM1
No normal CRM1 form directly calls this mapped route, though several integration/regression flows use it to update customer snapshots.
CRM2
The Customer layout map registers this as its update endpoint. Save a configurable customer layout and filter Network requests for Customer_updateData.
Related endpoints
Customer_getLayoutDetailsreads the same mapped field names.Customer_updateFieldis the legacy one-field mapped wrapper.Customer_editdocuments the CRM1 snake-case save path.