Customers
Create a customer
/a/Customer_new
Create a customer in the authenticated tenant, applying tenant rules for required contact numbers, duplicate names, default country, geocoding, and registered customer-created events.
When to use this endpoint
Use Customer_new when an integration needs a normal CRM customer record before creating jobs, assets, quotes, or invoices that refer to it. The endpoint returns the new ID; retrieve the record afterward when you need its final stored name, coordinates, timestamps, or defaults.
Do not use it as an upsert. It does not look up a customer by an external key, and duplicate-name behavior depends on tenant settings. Search or maintain your own Fieldmotion ID mapping before creating another record.
Authentication and permissions
The request must establish the tenant context with signed API-key authentication or a logged-in CRM session. The linked API user must be active.
The handler checks for an authenticated tenant but does not perform an additional page or role-permission check. A browser request may include a one-time _nonce; signed server-to-server requests normally omit it.
Parameters
Identity and contact fields
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | Trimmed customer name, maximum 178 bytes. Blank values are rejected. An exact existing name may be stored with a numeric suffix; see duplicate handling below. |
contact_name | String | No | Primary contact name, trimmed; maximum 82 bytes. CRM1 requires it in its own dialog, but the endpoint does not. |
landline | String | Conditional | Primary contact number, trimmed; maximum 38 bytes. It is required when the tenant's customers-require-landlines setting is enabled and must be unique among non-deleted customers when customer-landline-unique is enabled. |
mobile | String | No | Mobile number, trimmed; maximum 40 bytes. |
email | String | No | Primary email, trimmed; maximum 64 bytes. This endpoint does not validate email syntax. |
account_number | String | No | Customer account number, trimmed; maximum 58 bytes. The endpoint does not enforce account-number uniqueness. |
industry | String | No | Industry text, trimmed. |
notes | String | No | Initial customer notes, trimmed. |
Address and coordinates
| Parameter | Type | Required | Description |
|---|---|---|---|
street_address1 | String | No | First address line, trimmed. |
street_address2 | String | No | Second address line, trimmed. |
town | String | No | Town, trimmed; maximum 40 bytes. |
city | String | No | City, trimmed; maximum 40 bytes. |
county | String | No | County, trimmed; maximum 299 bytes. |
state | String | No | State or region, trimmed; maximum 255 bytes. |
postcode | String | No | Postcode, trimmed; maximum 20 bytes. |
country | String | No | Country code, trimmed; maximum 3 bytes. When omitted, the tenant's customer-default-country value is used. |
latitude | Number string | No | Converted to a float; defaults to 0. |
longitude | Number string | No | Converted to a float; defaults to 0. If both coordinates convert to zero and any main address field is present, the endpoint attempts to geocode the address. |
Relationships and structured values
| Parameter | Type | Required | Description |
|---|---|---|---|
parent_id | Integer string | No | Parent customer ID. Negative values become 0; this create handler does not verify that a positive parent exists. |
account_manager | Integer string | No | User ID stored as account manager; defaults to 0. This create handler does not validate the ID. |
department_id | Integer string | No | A positive numeric value triggers a post-insert Customer_setDepartmentId call, which validates the department and records a department change. |
billing_target | Integer string | No | Invoice-sync target; defaults to 0 for account behavior. -1 means this customer, -2 means its valid parent (falling back to itself), and a positive value names a specific customer. This handler stores the value without validating the target. |
custom_values | JSON object or array | No | Custom-field values. A JSON string is decoded, then the value is stored as JSON with arrays forced to object form. Omission stores {}. |
callback | String | No | Callback date/value. When supplied blank it is stored as SQL null; when omitted the database default is retained. |
email_accounting | String | No | Stored in customer metadata as email_accounting. |
email_extra | String | No | Additional email values. Whitespace is normalized and stored in metadata as newline-separated email_extra. |
account_number_sage | String | No | A non-blank value is trimmed and stored in metadata as legacy account_sage. |
_nonce | String | No | One-time browser form token. If supplied, it must exist and is consumed. Omit it from normal signed API integrations. |
Legacy type controls
The current handler accepts type, type_id, and do_not_run_trigger. A truthy do_not_run_trigger with type writes that integer during the insert without validating it. Otherwise, the presence—not the value—of type_id can trigger a post-insert setter that reads type. These parameters are retained for compatibility, not as a stable public calling pattern.
Example request
$result = FM_api('Customer_new', [
'name' => 'Northwind Service Centre',
'contact_name' => 'Alex Morgan',
'landline' => '028 9012 3456',
'email' => 'service@example.test',
'account_number' => 'NW-1104',
'street_address1' => '14 Harbour Road',
'town' => 'Belfast',
'postcode' => 'BT1 1AA',
'country' => 'GBR',
'custom_values' => json_encode([
'service_level' => 'gold',
]),
]);
Example response
{
"ok": 1,
"id": 1104
}
The response contains the integer ID but not the final stored record. If duplicate names are not allowed, the stored name might be Northwind Service Centre (2); fetch the ID with Customers_getById before persisting that display name elsewhere.
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. |
{"error":"missing or invalid parameter: name"} | name is absent or blank after trimming. |
{"error":"Contact Number was not set"} | The tenant requires customer contact numbers and landline is blank. |
{"error":"That landline is already in use by the following customers: ..."} | The tenant enforces unique contact numbers and a non-deleted customer already has the value. |
{"error":"<field> parameter too long. ..."} | A validated text field exceeds its endpoint limit. |
{"error":"failed to insert customer into database"} | The primary insert did not return a new ID. |
{"error":"this form appears to have been submitted already"} | A supplied _nonce is missing or has already been consumed. |
Legacy API errors may be returned with HTTP 200. Validate the decoded response for error before using id.
Behaviour and edge cases
- If
customer-name-allow-duplicateis not1, an exact case-insensitive duplicate is renamed to the first free numeric suffix beginning with(2). If the setting is1, the exact duplicate is stored. - Contact-number uniqueness considers non-deleted customers only and compares the stored value exactly.
- The endpoint does not validate parent, account-manager, billing-target, or account-number references during the primary insert.
- If both coordinates are zero and an address is present, geocoding is attempted synchronously. Failure does not fail customer creation; the stored coordinates remain zero.
cdateandlast_editeduse the API server's current timestamp, whilecreated_byrecords the authenticated user ID.- The base insert, optional department/type setters, and event listeners are not wrapped in one transaction. A customer can exist even if a post-insert relationship update does not succeed.
Side effects
- Inserts the customer and invalidates the customer cache.
- May make an external geocoding request before insertion when coordinates are absent and an address is present.
- A positive department ID can update
last_edited, write a customer change record, and add a customer audit-log entry throughCustomer_setDepartmentId. - After creation, fires the registered
Customer_newevent. A tenant with the Zapier customer-created hook enabled sends the full new customer row to the registered target URL; the hook may remove its subscription if the target asks to unsubscribe.
See it in Fieldmotion
CRM1
Open Customers, open browser developer tools, and select Create Customer. Submit the dialog and filter Network requests for Customer_new. CRM1 includes a one-time _nonce, requires Contact Name in the dialog, and conditionally requires Contact Number before it sends the request. The endpoint response then redirects the UI to the new customer's edit page.
CRM2
No production CRM2 JavaScript caller of Customer_new was found. CRM2's Customers → Create Customer modal uses the configurable Customer Create layout, whose create mapping calls Customer_createData instead. Do not use that screen as a wire example for this endpoint; use CRM1 or a signed API request.
Related endpoints
Customers_getByIdretrieves the completed record and its final stored name.Customers_listchecks existing records before creation and returns the new customer in subsequent lists.Customer_setTypeis the safer explicit follow-up for a customer type because it validates the type and exposes trigger results.Customer_createDatais the layout-driven CRM2 create path and has a different contract.