POST

Customer.Add

Add a customer into the system. If the customer already exists, the response returns the existing customer id and the matching field. Send force=1 to create a new customer anyway. The method validates folder permission, saves source and affiliate log data, saves custom fields from User.Basic, pushes the added customer to the team, and runs add_lead automation.

Required Choice

Send at least one complete option from the list below.

OptionAccepted FieldsExplanation
1name or phone or mobile or email or company_idOne of these values is required to create the record.

Permissions

  • User must be allowed to add customers.
  • If folder_id is sent, user must be allowed to see this folder or be owner/manager in the organization.

Action

  • Adds a customer to the Customers table.
  • Checks if the customer already exists.
  • Adds a log row with the new source.
  • Saves source, affiliate, common fields, tags, folder/status, and custom fields from User.Basic.

Push Service

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

Automation

Runs automation event add_lead with customer_id and submitted parameters such as source, folder_id, tag, affiliate, and custom fields.

Special Instructions

  • If customer exists, response includes existing_customer_id and duplicate details.
  • Send force=1 to create a new customer even when a duplicate exists.
  • Use User.Basic for folders, statuses, tags, and custom field definitions.

Required Parameters

No body parameters are required for this function.

Optional Parameters

NameTypeSampleWhat it gives
name
post
stringJohn DemoCustomer name. Required only when no phone, email, mobile, or company_id is sent.
email
post
string[email protected]Customer email. Email or phone is recommended.
second_email
post
string[email protected]Secondary email shown on the customer when enabled for the account.
phone
post
string0500000000Primary customer phone. Saved to the customer mobile field after normalization.
mobile
post
string0500000000Alias for the primary customer phone.
second_phone
post
string0500000001Secondary customer phone. Saved to the customer phone field after normalization.
company
post
stringDemo LtdCompany/business name for the customer.
company_id
post
string123456789Company identifier. Can be used for duplicate detection when checkUnique is company_id.
csv_id
post
int22Import/batch id when the customer is created from an import flow.
source
post
stringwebsiteLead/customer source used for filtering and reporting.
affiliate
post
stringpartner-42Affiliate/source partner value. Saved on the customer and copied to source log when supported.
website
post
stringhttps://example.comCustomer website when the account shows this common field.
password
post
stringcustomer-passCustomer password/reference field when the account shows this common field.
note
post
stringAsked for a quoteGeneral customer note.
notes
post
stringAsked for a quoteAlias for note.
address
post
string12 Demo StreetCustomer address.
city
post
stringTel AvivCustomer city.
city_name
post
stringTel AvivCity display name when sending a numeric city id in city or city_id.
city_id
post
int10City id from the city catalog when available.
folder_id
post
int1Initial folder/status id. Use User.Basic folders/statuses for valid values.
folder
post
int|string1Alias for folder_id. Multiple folders can be sent as comma-separated ids.
status_id
post
int1Initial customer status when the account separates status from folder.
status
post
string1Alias for status_id.
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.
tag
post
string1,2Comma-separated tag ids from User.Basic tags.
extra_fields
post
json{"vip_level":"gold"}JSON object for customer custom fields. Read the allowed keys, labels, types, encryption flags, and options from User.Basic field_settings.customer.extra_fields before sending.
extra_fields[field_name]
post
mixedgoldAlternative form-data style for one custom field value. Replace field_name with a configured custom field key from User.Basic field_settings.customer.extra_fields.
cf-field_name
post
mixedgoldCustom-field alias. Replace field_name with the configured custom field name/en key from User.Basic field_settings.customer.extra_fields. Unknown custom fields are rejected by the app validator.
parent_customer_id
post
int456Creates the customer as a sub-customer under this parent customer. Also accepts parent_cust_IIId.
parent_cust_IIId
post
int456Alias for parent_customer_id.
room_customer_name
post
int1When 1, duplicate detection also checks the customer name for room-style flows.
customer_add_from_email
post
int1Marks this add as created from email. Marks this customer as created from email so related email workflows can use the value.
extension
post
string101Phone extension for call-center or softphone flows. The value can be included in the push payload after create.
data_value_for_socket
post
stringcallOptional push payload marker for call-center or softphone flows.
checkUnique
post
stringemailDuplicate check mode: email, phone, mobile, or company_id. Default follows contactus behavior. Duplicate responses explain the exact match in duplicate_by, duplicate_value, and duplicate_reason.
upsert
post
int0When 1, update an existing duplicate customer instead of returning already=1. Response has exists=1, is_new=0, upserted=1, and customer_id of the updated customer. force=1 overrides upsert and creates a new customer.
glob_check_already_or_not
post
int1When 1, duplicate customers return already=1. When 0, the matching customer is updated. force=1 overrides this and creates a new customer.
force
post
int0When 1, create a new customer even if duplicate detection finds an existing customer. The response returns forced=1, existing_customer_id, duplicate_customer_id, duplicate_by, duplicate_value, and duplicate_reason when this happens.
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.

Authorization: Bearer YOUR TOKEN

Sample Request

{
    "url": "\/app\/Customer.Add",
    "method": "POST",
    "headers": {
        "Authorization": "Bearer YOUR TOKEN"
    },
    "body": {
        "name": "John Demo",
        "phone": "0500000000",
        "source": "website",
        "affiliate": "partner-42",
        "folder_id": "1",
        "force": "0",
        "extra_fields": "{\"vip_level\":\"gold\"}"
    },
    "url_user": "https:\/\/{user}.bull36.com\/app\/Customer.Add",
    "url_domain": "https:\/\/{domain}\/app\/Customer.Add"
}

Endpoint

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

Sample Output

{
    "success": 1,
    "exists": 0,
    "is_new": 1,
    "forced": 0,
    "existing_customer_id": null,
    "duplicate_customer_id": null,
    "exists_by": null,
    "exists_reason": null,
    "duplicate_by": null,
    "duplicate_value": null,
    "duplicate_reason": null,
    "message": "Customer Created",
    "contactus_id": "123",
    "customer_id": "123",
    "id": "123"
}

Existing Customer Response

{
    "success": 0,
    "exists": 1,
    "is_new": 0,
    "message": "Customer already exists",
    "existing_customer_id": "123",
    "customer_id": "123",
    "duplicate_by": "email",
    "duplicate_value": "[email protected]",
    "duplicate_reason": "same email"
}

Fail Response

{
    "success": 0,
    "message": "Missing required parameter. Send at least one of name, phone, mobile, email, company_id."
}

JavaScript Example

const token = 'YOUR TOKEN';

// Load field settings once after login and build your form from them.
const basicRes = await fetch('/app/User.Basic', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}` }
});
const basic = await basicRes.json();
const customerFields = basic.data.field_settings.customer.extra_fields;

const body = new URLSearchParams({
  name: 'John Demo',
  phone: '0500000000',
  source: 'website',
  affiliate: 'partner-42',
  folder_id: '1',
  checkUnique: 'email',
  glob_check_already_or_not: '1',
  force: '0',
  extra_fields: JSON.stringify({ vip_level: 'gold' })
});

// You may also send one custom field as cf-field_name when that key exists in User.Basic.
body.set('cf-vip_level', 'gold');

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

const data = await res.json();
if (data.exists && !data.is_new) {
  console.log('customer already exists', {
    existing_customer_id: data.existing_customer_id || data.customer_id,
    duplicate_by: data.duplicate_by,
    duplicate_value: data.duplicate_value,
    duplicate_reason: data.duplicate_reason
  });
} else {
  console.log('created customer id', data.customer_id || data.id, { forced: data.forced, existing_customer_id: data.existing_customer_id });
}
console.log({ data, customerFields });

Error Example

{
    "success": 0,
    "exists": 1,
    "is_new": 0,
    "already": 1,
    "already_id": "123",
    "existing_customer_id": "123",
    "duplicate_customer_id": "123",
    "exists_by": "email",
    "exists_reason": "same email",
    "duplicate_by": "email",
    "duplicate_value": "[email protected]",
    "duplicate_reason": "same email",
    "customer_id": "123",
    "id": "123",
    "message": "Customer already exists"
}