# How to Configure Client Fields?

Configuring client fields lets you **define custom fields** and **control their visibility** for operators. Without custom fields, only a limited set of standard client-card fields is available.

## When You'll Need This

- You need to add additional fields to the client card (for example, "Client Number", "Category", "Registration Date").
- Integration with external systems requires storing additional client information.
- You need to extend the standard client profile for your business processes.

## What's Important to Know

- **Client Fields** (`/settings-page/client-fields`): first block — custom field definitions (form + JSON); below — **visibility** toggles and optional visibility JSON. **One Save button in the page header** stores **both** `client_fields_json` **and** `client_card_fields` — there is no second Save inside the visibility card.
- **Same visibility UI** is also available under **Field editor in the Client Card** (`/settings-page/op-settings/client-fields`, operator panel **Settings** menu): visibility only; save uses the **op-settings header Save** (batch operator-panel settings; needs `settings` permission). See [Field editor in the Client Card](/en/settings/how-to/configure-client-card-fields.md).
- **Standard fields** — native OpClients columns: `phone`, `bot_id`, `bot_name`, `fullName` (from `full_name`). `clientType`, `whiteLabel` in samples may be custom `extra_data` keys or legacy.
- **Custom field values** are stored in the client's `extra_data`.
- **Field form and JSON** — basic inputs (key, type, label) plus optional properties; full list in the [Client fields JSON reference](/en/settings/reference/client-fields-json.md). The field editor includes **JSON examples** snippets.
- **Client Portal (self-registration):** toggle **Show on Client Portal registration** adds the field to the `/register` form in Client Portal. Requires `portal_registration_enabled` on the instance (instance settings, root). See [Configure instance settings](/en/settings/how-to/configure-instance.md).

## Before You Start

- [x] You are logged in with administrator or integrator rights.
- [x] You have permission to edit client fields (`canSave` for the users section).

## Step-by-step

### 1. Open Client Fields

1. Open the **Settings** module via the menu or at `/settings-page`.
2. In the side menu, expand **Bots** (Process Library).
3. Click **Client Fields** (`/settings-page/client-fields`).

### 2. Define fields and visibility

1. In the **first** block, review or edit the field list and JSON (`custom_fields_json`). Use **Add field** or edit JSON ([reference](/en/settings/reference/client-fields-json.md)).
2. In the **second** block, set visibility toggles for standard and custom fields.
3. Optionally expand **visibility JSON** — same data as toggles; editors stay in sync.
4. Click the **single Save** in the **page header** to persist **both** field definitions and visibility. A success notification appears after a successful save.

### 3. Alternative: visibility only in op-settings

Open **Field editor in the Client Card** (`/settings-page/op-settings/client-fields`) from operator panel **Settings** for the same visibility controls; use the on-page link to **Client Fields** for full field definition. Save with the op-settings header button. Details: [Field editor in the Client Card](/en/settings/how-to/configure-client-card-fields.md).

## JSON examples (same as the **JSON examples** block in the UI)

At the bottom of the **Client Fields** page, a selector offers five scenarios — the JSON below matches that content. Names in the UI are short; here each example explains **what it is meant to demonstrate**. Each block is the **field object payload** (under `custom_fields_json` when saved). Copy it, rename keys to match your project, then click **Save** in the page header.

**Two levels of keys:** outer keys (`full_name`, `store_id`, etc.) are **your field names** in client data; inner keys (`type`, `label`, `association`…) are **schema parameters** the UI understands. After each sample, a short list explains why each key is there.

### Basic

Three standalone fields of different types: short text, date, and integer with a **default** value for loyalty points. Use it as a minimal starter without validation or cross-field logic.

```json
{
  "full_name": {
    "type": "STRING",
    "label": "Full name"
  },
  "birth_date": {
    "type": "DATE",
    "label": "Date of birth"
  },
  "loyalty_points": {
    "type": "INTEGER",
    "label": "Points",
    "default": "0"
  }
}
```

**Keys and why:** `type` — data type in the form; `label` — caption for operators; `default` — pre-filled value (here for the numeric field). Names like `full_name`, `birth_date`, `loyalty_points` are only examples — use your own keys.

### Date / time + validation

Two time fields (`type_string`: time, `HH:mm` format). Both are required; the **end** field adds a **cross-field check** via `validate`: end time must be after start. That object is not exposed as separate toggles in the form — configure it in JSON.

```json
{
  "start_time": {
    "type": "STRING",
    "label": "Start",
    "type_string": "time",
    "format": "HH:mm",
    "string_input": {},
    "rules": ["required"]
  },
  "end_time": {
    "type": "STRING",
    "label": "End",
    "type_string": "time",
    "format": "HH:mm",
    "string_input": {},
    "rules": ["required"],
    "validate": {
      "required_field_not_empty": "start_time",
      "rules": {
        "type": "time",
        "val_from_field": "start_time",
        "action": "gt"
      }
    }
  }
}
```

**Keys and why:** again `type` and `label`. For time-as-string fields: `type_string`: `"time"` tells the UI to treat input as time; `format` is the mask (`HH:mm`); `string_input`: `{}` enables the matching input widget. `rules`: `["required"]` marks the field mandatory (also available from the form). The **`validate`** object is a **cross-field** rule: `required_field_not_empty` requires `start_time` to be set; nested `rules` compares end time to `start_time` with action `gt` (greater than — strictly later). Exact `validate` shapes depend on the scenario — use this snippet as the pattern.

### Linked field

A field with **`association`** stores the linked record’s ID; a second field shows a human-readable **label** (e.g. name), is hidden in the quick-create popup, and is read-only. Typical “stored ID + display label for operators” pattern.

```json
{
  "store_id": {
    "type": "INTEGER",
    "label": "Store",
    "association": {
      "as": "store_name",
      "model_field_label": "name",
      "fetch_limit": 500
    }
  },
  "store_name": {
    "type": "STRING",
    "label": "Store name",
    "hidden_in_create_popup": true,
    "non_editable": "true"
  }
}
```

**Keys and why:** **`association`** describes a link to another entity: `as` — the **other field key** in this JSON that receives the display label; `model_field_label` — which field from the linked record to show; `fetch_limit` — how many rows can be loaded for the picker. On `store_name`: `hidden_in_create_popup`: `true` hides it in quick create; `non_editable`: `"true"` makes it read-only (the label is usually filled from `store_id`).

### Row highlighting

Planned and actual time fields; one field uses **`sting_highlight`** so table rows get **conditional colours** based on comparing the two times. This is advanced behaviour and is wired **only** through JSON, not the field form.

```json
{
  "planned_finish": {
    "type": "STRING",
    "label": "Planned",
    "type_string": "time",
    "format": "HH:mm",
    "string_input": {}
  },
  "actual_finish": {
    "type": "STRING",
    "label": "Actual",
    "type_string": "time",
    "format": "HH:mm",
    "string_input": {},
    "sting_highlight": {
      "type": "STRING",
      "highlight_rules": {
        "type": "time",
        "rules": [
          { "0": "actual_finish", "1": "planned_finish", "action": "gt",  "color": "red"   },
          { "0": "actual_finish", "1": "planned_finish", "action": "lte", "color": "green" }
        ]
      }
    }
  }
}
```

**Keys and why:** for plain time fields — again `type_string`, `format`, `string_input`. **`sting_highlight`** (spelling as in the product) enables conditional **row** colouring; inside **`highlight_rules`**, `type`: `"time"` sets the comparison mode; the **`rules`** array lists conditions: `"0"` and `"1"` reference other field keys, `action` (`gt`, `lte`, …) is the comparison, `color` is the row colour when the condition matches.

### Table totals + link

A numeric field with a **footer total** (`total_sum`), width, alignment, and sorting; a second string field uses **`display_type`: link** so the value opens as a URL. Flags like `total_sum` are set in JSON when the form does not offer them.

```json
{
  "amount": {
    "type": "FLOAT",
    "label": "Amount",
    "width": "90",
    "align": "end",
    "sortable": "true",
    "total_sum": true
  },
  "invoice_url": {
    "type": "STRING",
    "label": "Invoice",
    "display_type": "link",
    "width": "60"
  }
}
```

**Keys and why:** for the clients table — `width` (column width in px), `align` (`end` is typical for numbers), `sortable`: `"true"` enables sorting; **`total_sum`**: `true` includes the field in the footer total. For the link column: **`display_type`**: `"link"` opens the cell value as a URL in a new tab (see also the [reference](/en/settings/reference/client-fields-json.md)).

## What Happens Next

- Custom field definitions are stored in `client_fields_json` (instance settings).
- Visibility is stored in `client_card_fields` (operator panel settings).
- Operators see and fill fields according to the toggles / visibility JSON.

## How to Verify Everything Worked

- On **Client Fields**, confirm fields and toggles match what you want.
- Open a client card in the operator panel and verify the right fields appear.

## Related Materials

- [Client fields JSON reference](/en/settings/reference/client-fields-json.md) — all properties inside `custom_fields_json`
- [Configure user fields](/en/settings/how-to/configure-user-fields.md)
- [Field editor in the Client Card (op-settings)](/en/settings/how-to/configure-client-card-fields.md) — same visibility block, different save affordance
- [Configure instance settings](/en/settings/how-to/configure-instance.md) — `portal_registration_enabled`, `client_portal_url`

## Important Notes

- ⚠️ On **Client Fields**, one header **Save** writes **both** parts. On **op-settings/client-fields**, saving uses the op-settings header **Save** (`settings` permission).
- ⚠️ **Deleting fields**: data in `extra_data` may be lost.
- 💡 **Backup**: make a copy of the JSON before major changes.
