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.
| Option | Accepted Fields | Explanation |
|---|---|---|
| 1 | name or phone or mobile or email or company_id | One 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
| Name | Type | Sample | What it gives |
|---|---|---|---|
namepost | string | John Demo | Customer name. Required only when no phone, email, mobile, or company_id is sent. |
emailpost | string | [email protected] | Customer email. Email or phone is recommended. |
second_emailpost | string | [email protected] | Secondary email shown on the customer when enabled for the account. |
phonepost | string | 0500000000 | Primary customer phone. Saved to the customer mobile field after normalization. |
mobilepost | string | 0500000000 | Alias for the primary customer phone. |
second_phonepost | string | 0500000001 | Secondary customer phone. Saved to the customer phone field after normalization. |
companypost | string | Demo Ltd | Company/business name for the customer. |
company_idpost | string | 123456789 | Company identifier. Can be used for duplicate detection when checkUnique is company_id. |
csv_idpost | int | 22 | Import/batch id when the customer is created from an import flow. |
sourcepost | string | website | Lead/customer source used for filtering and reporting. |
affiliatepost | string | partner-42 | Affiliate/source partner value. Saved on the customer and copied to source log when supported. |
websitepost | string | https://example.com | Customer website when the account shows this common field. |
passwordpost | string | customer-pass | Customer password/reference field when the account shows this common field. |
notepost | string | Asked for a quote | General customer note. |
notespost | string | Asked for a quote | Alias for note. |
addresspost | string | 12 Demo Street | Customer address. |
citypost | string | Tel Aviv | Customer city. |
city_namepost | string | Tel Aviv | City display name when sending a numeric city id in city or city_id. |
city_idpost | int | 10 | City id from the city catalog when available. |
folder_idpost | int | 1 | Initial folder/status id. Use User.Basic folders/statuses for valid values. |
folderpost | int|string | 1 | Alias for folder_id. Multiple folders can be sent as comma-separated ids. |
status_idpost | int | 1 | Initial customer status when the account separates status from folder. |
statuspost | string | 1 | Alias for status_id. |
sub_list_datapost | string | 5 | Folder sub-status value. Requires folder/folder_id. |
sub_list_data_namepost | string | stage | Name/key used for folder_sub_status when sub_list_data is sent. |
internal_sub_status_listpost | string | 2 | Internal sub-status value saved under folder_sub_internal_status when sub_list_data is sent. |
tagpost | string | 1,2 | Comma-separated tag ids from User.Basic tags. |
extra_fieldspost | 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 | mixed | gold | Alternative 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_namepost | mixed | gold | Custom-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_idpost | int | 456 | Creates the customer as a sub-customer under this parent customer. Also accepts parent_cust_IIId. |
parent_cust_IIIdpost | int | 456 | Alias for parent_customer_id. |
room_customer_namepost | int | 1 | When 1, duplicate detection also checks the customer name for room-style flows. |
customer_add_from_emailpost | int | 1 | Marks this add as created from email. Marks this customer as created from email so related email workflows can use the value. |
extensionpost | string | 101 | Phone extension for call-center or softphone flows. The value can be included in the push payload after create. |
data_value_for_socketpost | string | call | Optional push payload marker for call-center or softphone flows. |
checkUniquepost | string | email | Duplicate 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. |
upsertpost | int | 0 | When 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_notpost | int | 1 | When 1, duplicate customers return already=1. When 0, the matching customer is updated. force=1 overrides this and creates a new customer. |
forcepost | int | 0 | When 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. |
followuppost | datetime | 2026-07-20 10:00:00 | UTC 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.AddSample 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"
}