POST

Customer.Update

Update an existing customer. The method validates folder permission, validates custom fields from User.Basic, blocks duplicate email/phone/mobile/company_id/name conflicts, pushes the changed customer to the team, and runs customer.updated automation when enabled.

Permissions

  • On a company subdomain (e.g. https://{user_domain}.bull36.com) the user must match that Host — Login and protected APIs reject another company with success=0, error user_not_in_company. On a main brand host (bull36.com, biz1.co.il, mastrocrm.com, …) the company domain gate is skipped.
  • User must be allowed to edit this customer.
  • If folder_id is changed, user must be allowed to see this folder or be owner/manager in the organization.

Action

  • Updates the customer row.
  • Validates folder/status access.
  • Validates custom fields from User.Basic.
  • Blocks duplicate email, phone, mobile, company_id, or name conflicts.

Push Service

Pushes the changed customer to team members that can see this customer.

Automation

Runs automation event customer.updated with customer_id and changed fields when enabled.

Special Instructions

  • On a company subdomain (e.g. https://{user_domain}.bull36.com) the user must match that Host — Login and protected APIs reject another company with success=0, error user_not_in_company. On a main brand host (bull36.com, biz1.co.il, mastrocrm.com, …) the company domain gate is skipped.
  • If a sent email/phone/company id belongs to another customer, the response returns existing_customer_id and duplicate details.

Required Parameters

NameTypeSampleExplanation
customer_id
post
int123Customer id to update. You may also send cust_id.

Optional Parameters

NameTypeSampleWhat it gives
name
post
stringJohn Demo UpdatedCustomer name.
email
post
stringjohn@example.comCustomer email. If another customer already has this email, the route returns exists=1 with duplicate_by=email and existing_customer_id.
second_email
post
stringbilling@example.comUpdates the secondary email when this field is enabled.
phone
post
string0500000000Primary customer phone. Saved to the customer mobile field after normalization. If another customer already has this phone/mobile, the route returns duplicate_by=phone or duplicate_by=mobile.
mobile
post
string0500000000Alias for the primary customer phone. It participates in the same duplicate check as phone.
second_phone
post
string0500000001Updates the secondary phone. Saved to the customer phone field after normalization.
company
post
stringDemo LtdUpdates the customer company/business name.
company_id
post
string123456789Updates the company identifier. If checkUnique=company_id and another customer already has this value, the route returns duplicate_by=company_id.
checkUnique
post
stringemailDuplicate check mode for the edited values: email, phone, mobile, or company_id. Default follows the same customer rules as Customer.Add.
source
post
stringwebsiteUpdates the lead/customer source.
website
post
stringhttps://example.comUpdates the website field when enabled.
password
post
stringcustomer-passUpdates the customer password/reference field when enabled.
note
post
stringUpdated noteUpdates the customer note.
address
post
string12 Demo StreetUpdates the address.
city
post
stringTel AvivUpdates the city.
folder_id
post
int1Moves the customer to a folder/status id from User.Basic folders/statuses.
folder
post
int|string1Alias for folder_id. Multiple folders can be sent as comma-separated ids.
status_id
post
int1Updates the customer status when the account uses status_id.
tag
post
string1,2Replaces/updates comma-separated tag ids from User.Basic tags.
extra_fields
post
json{"vip_level":"silver"}JSON object for customer custom fields. Allowed keys/types come from User.Basic field_settings.customer.extra_fields.
extra_fields[field_name]
post
mixedsilverAlternative form-data style for one custom field value. Replace field_name with a key from User.Basic field_settings.customer.extra_fields.
cf-field_name
post
mixedsilverCustom-field alias. Replace field_name with a configured custom field key from User.Basic field_settings.customer.extra_fields. Unknown custom fields are rejected.
sub_list_data
post
string5Folder sub-status value. Requires folder/folder_id.
sub_list_data_name
post
stringstageName/key used for folder_sub_status when sub_list_data is sent.
internal_sub_status_list
post
string2Internal sub-status value saved under folder_sub_internal_status when sub_list_data is sent.
parent_customer_id
post
int456Moves/keeps this customer under a parent customer relation. Also accepts parent_cust_IIId.
parent_cust_IIId
post
int456Alias for parent_customer_id.
room_customer_name
post
int1When 1 and name is sent, duplicate detection also checks whether another customer already has the same cleaned name.
followup
post
datetime2026-07-20 10:00:00UTC follow-up date/time saved on the customer. Send UTC date/time as Y-m-d H:i:s, for example 2026-07-20 10:00:00. The SDK converts user local Date/local datetime input to UTC before posting.

Authentication

Send the bearer token returned by Login in the request header. The user must be from the same company domain as this Host — a token from another company is rejected (user_not_in_company).

Authorization: Bearer YOUR TOKEN

Sample Request

{
    "url": "\/app\/Customer.Update",
    "method": "POST",
    "headers": {
        "Authorization": "Bearer YOUR TOKEN"
    },
    "body": {
        "customer_id": "123",
        "name": "John Demo Updated",
        "email": "john@example.com",
        "checkUnique": "email",
        "extra_fields": "{\"vip_level\":\"silver\"}"
    },
    "url_user": "https:\/\/{user}.bull36.com\/app\/Customer.Update",
    "url_domain": "https:\/\/{domain}\/app\/Customer.Update"
}

Endpoint

POST /app/Customer.Update
POST https://{user}.bull36.com/app/Customer.Update
POST https://{domain}/app/Customer.Update

Sample Output

{
    "success": 1,
    "exists": 0,
    "is_new": 0,
    "message": "Customer Updated",
    "customer_id": "123",
    "id": "123",
    "automation_event": "customer.updated",
    "socket_event": "customer.updated"
}

Existing Customer Response

{
    "success": 0,
    "exists": 1,
    "is_new": 0,
    "message": "Customer already exists",
    "customer_id": "123",
    "existing_customer_id": "456",
    "duplicate_by": "email",
    "duplicate_value": "john@example.com",
    "duplicate_reason": "same email"
}

Fail Response

{
    "success": 0,
    "message": "Customer not found or permission denied"
}

JavaScript Example

const token = 'YOUR TOKEN';
const body = new URLSearchParams({
  customer_id: '123',
  name: 'John Demo Updated',
  email: 'john@example.com',
  checkUnique: 'email',
  extra_fields: JSON.stringify({ vip_level: 'silver' })
});

const res = await fetch('/app/Customer.Update', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}` },
  body
});

const data = await res.json();
if (data.exists) {
  console.log('cannot update because another customer already exists', {
    editing_customer_id: data.customer_id,
    existing_customer_id: data.existing_customer_id,
    duplicate_by: data.duplicate_by,
    duplicate_value: data.duplicate_value,
    duplicate_reason: data.duplicate_reason
  });
} else {
  console.log('updated customer id', data.customer_id || data.id);
}
console.log(data);

Error Example

{
    "success": 0,
    "exists": 1,
    "is_new": 0,
    "already": 1,
    "already_id": "456",
    "existing_customer_id": "456",
    "duplicate_customer_id": "456",
    "duplicate_by": "email",
    "duplicate_value": "john@example.com",
    "duplicate_reason": "same email",
    "customer_id": "123",
    "id": "123",
    "message": "Customer already exists"
}