> For the complete documentation index, see [llms.txt](https://docs.saleschat.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.saleschat.pro/principles/events-and-attributes.md).

# Events & Attributes

#### Overview

SalesChat tracks two types of data for your leads and users:

* **Attributes** — Attributes are custom fields you can attach to your **users** and **leads** (e.g., process, product code, policy number)
* **Events** — things that happen, carrying event-scoped attributes (e.g., stage change, disposition update, call details)

Automations are triggered based on events and attributes are used by attribute matcher to filter such events.

#### Permanent Attributes

Permanent attributes are properties that rarely change and are scoped for the life of the lead.

Permanent attributes are key-value pairs stored on a lead or user. They accumulate over time — each update merges new values with existing ones.

**How they work:**

```
API call 1:  { "process": "Issuance" }     → Lead has: { process: Issuance }
API call 2:  { "product_code": "P1" }      → Lead has: { process: RM, product_code: P1 }
API call 3:  { "process": "Sales" }        → Lead has: { process: Sales, product_code: P1 }
```

* New keys are added
* Existing keys are updated (latest value wins)
* Keys not included in the update are preserved

**Use cases:** CRM sync fields, customer segments, agent assignments, any data that defines "who" the lead or user is.

#### Attribute Keys and Values

`process`, `Process`, and `PROCESS` are three different attributes, and a lead can hold all three at once. Pick one spelling and use it in every integration that writes the attribute. Lowercase with underscores (`policy_number`) is the convention.

**Value Types**

<table><thead><tr><th width="156">Type</th><th width="119">Supported</th><th>Notes</th></tr></thead><tbody><tr><td><strong>Text</strong></td><td>Yes</td><td>Stored exactly as sent — no trimming, no case changes</td></tr><tr><td><strong>Number</strong></td><td>Yes</td><td></td></tr><tr><td><strong>true / false</strong></td><td>Yes</td><td></td></tr><tr><td><strong>List</strong></td><td>Yes</td><td>Replaced whole on update, never merged item by item</td></tr><tr><td><strong>Nested object</strong></td><td>Yes</td><td>Merged field by field — see below</td></tr></tbody></table>

**Setting, clearing and removing**

<table><thead><tr><th width="182">What you send</th><th width="229">Result</th><th width="328">Attribute Matcher sees</th></tr></thead><tbody><tr><td><code>"process": "RM"</code></td><td>Value stored</td><td><em>set</em>, value <code>RM</code></td></tr><tr><td><code>"process": ""</code></td><td>Empty value stored</td><td><strong>set</strong>, value empty</td></tr><tr><td><code>"process": null</code></td><td>Value cleared, key stays in the attribute list</td><td><strong>not set</strong></td></tr><tr><td>key omitted</td><td>Previous value preserved</td><td>unchanged</td></tr></tbody></table>

**Nested Objects**

Nested objects are stored and merged field by field, the same way top-level keys are:

```
API call 1:  { "address": { "city": "Mumbai" } }       → { address: { city: Mumbai } }
API call 2:  { "address": { "pincode": "400001" } }    → { address: { city: Mumbai, pincode: 400001 } }
```

However, **no field inside a nested object can be addressed downstream.** The [Attribute Matcher ](/principles/attribute-matcher.md)sees the property `address`; it cannot see `address.city`.

**Naming rules**

<table><thead><tr><th width="248">Rule</th><th width="463">Why</th></tr></thead><tbody><tr><td>Don't start a key with <code>sc_</code></td><td>Reserved for SalesChat-defined fields. Keys in this namespace are excluded from reporting.</td></tr><tr><td>Don't use <code>.</code> in a key name</td><td>Read as a nesting separator, which can break attribute indexing.</td></tr><tr><td>Don't use a blank key name</td><td>Rejected.</td></tr><tr><td>Keep one value type per key</td><td>Sending <code>score: 42</code> for one lead and <code>score: "high"</code> for another can break attribute indexing for your organisation.</td></tr></tbody></table>

***

#### Events

Events represent things that happen to a lead. Each event has a **type** and carries **event attributes** that are scoped to that specific event.

**Key difference from permanent attributes:** Event attributes are properties that change very often and are scoped for the life of the event. The next event has its own attributes.

**API — Disposition update (triggers an event):**

`PUT /v2/orgs/{orgId}/contact/{contactId}/disposition`

```json
{
    "stage": "INTERESTED",
    "disposition": "WARM",
    "call_time": "10:30",
    "payment_amount": "5000"
}
```

All fields beyond `stage` and `disposition` are accepted as additional event attributes.

#### How Attributes and Events Work Together

Event triggers automation, attribute matcher matches / filters based on the attributes.

```
Permanent attributes (from lead profile)
    +
Event attributes (from the triggering event)
    =
Merged attributes → evaluated against matcher conditions
```

**If a key exists in both, the event attribute takes precedence.**

**Example:**

Lead has permanent attributes: `{ process: "RM", product_code: "P1" }`

A disposition event arrives with: `{ stage: "INTERESTED", disposition: "WARM" }`

The matcher evaluates against the merged set:

```
process = RM              (from permanent)
product_code = P1         (from permanent)
stage = INTERESTED        (from event)
disposition = WARM        (from event)
```

You can configure matcher conditions against any of these — e.g., trigger automation when `stage = INTERESTED` AND `process = RM`.
