> For the complete documentation index, see [llms.txt](https://flapjax.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://flapjax.gitbook.io/docs/core-concepts/data-types.md).

# Data Types

**Audience:** technical readers and power users. Anyone defining attributes, building rules and segments, or integrating over the API, who needs to know which field types exist and how they behave.

Every field on a person, a stack record, a list or a custom-action payload carries a **data type**. That one fact decides three things: which values are valid, which comparison operators the rule and segment builder offers, and how a value is coerced as it flows through an automation.

This page is the single reference for that system. It consolidates the partial lists in [people-attributes](/docs/your-data/people/attributes.md), data-model and the [glossary](/docs/start-here/key-concepts.md) entry for *Attribute*.

***

## 1. How the catalogue works

The platform defines the set of data types. It is a fixed catalogue, and no organization extends it. Each type carries:

* a **key**, the machine name used in API payloads, plus a **display name**, the label shown in the attribute-type dropdown
* one or more **scopes**, from `stack`, `person`, `system` and `custom-action`, which govern where the type appears. See [§3](#3-scopes--where-a-type-shows-up).

The app builds its attribute-type dropdowns straight from this catalogue, so the tables below match exactly what you see as you create an attribute.

***

## 2. The full catalogue

Every type seeded today, after all forward migrations.

**User-selectable** means the type appears in an attribute-creation dropdown, which it does by carrying a `stack`, `person` or `custom-action` scope. **System-derived** types carry the `system` scope alone. They back built-in fields and internal state, and no attribute-creation dropdown ever offers them.

| Key                       | Display name             | What it stores                                                                                         | Scopes                       | Selectable?              |
| ------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------ | ---------------------------- | ------------------------ |
| `string`                  | Text (String)            | Plain UTF-8 text                                                                                       | stack, person, custom-action | Yes                      |
| `integer`                 | Number (Integer)         | Whole number                                                                                           | stack, person, custom-action | Yes                      |
| `float`                   | Decimal (Float)          | Floating-point number                                                                                  | stack, person, custom-action | Yes                      |
| `boolean`                 | True/False (Boolean)     | `true` / `false`                                                                                       | stack, person, custom-action | Yes                      |
| `hour`                    | Hour                     | Hour of day, `0`–`23`                                                                                  | stack, person                | Yes                      |
| `date`                    | Date                     | Calendar date `YYYY-MM-DD`                                                                             | stack, person, custom-action | Yes                      |
| `datetime`                | Date & Time              | Instant, ISO-8601 / RFC-3339                                                                           | stack, person, custom-action | Yes                      |
| `select`                  | Single Choice (Select)   | One value from a configured option list                                                                | stack, person                | Yes                      |
| `multiselect`             | Multiple Choice (Select) | Set of values from a configured list                                                                   | stack, person                | Yes                      |
| `country`                 | Country List             | ISO 3166-1 alpha-2/alpha-3 code                                                                        | stack, person                | Yes                      |
| `currency`                | Currency List            | ISO 4217 code (`USD`, `EUR`, …)                                                                        | stack, person                | Yes                      |
| `stack`                   | Related Stack            | Reference to a record in another stack                                                                 | stack, person                | Yes                      |
| `person`                  | Related Person (One)     | Reference to a single person                                                                           | stack                        | Yes (stack only)         |
| `people`                  | Related People (Many)    | References to multiple people                                                                          | stack                        | Yes (stack only)         |
| `object`                  | Object (JSON)            | Arbitrary JSON object                                                                                  | custom-action                | Yes (custom action only) |
| `array_objects`           | Array of Objects         | JSON array of objects                                                                                  | custom-action                | Yes (custom action only) |
| `array_strings`           | Array of Strings         | JSON array of strings                                                                                  | custom-action                | Yes (custom action only) |
| `array_integers`          | Array of Integers        | JSON array of integers                                                                                 | custom-action                | Yes (custom action only) |
| `encrypted_string`        | Encrypted Text           | Text stored encrypted at rest (PII)                                                                    | stack, person                | Yes                      |
| `access_client`           | Access Client            | Reference to an API access client                                                                      | system                       | No                       |
| `labels`                  | Labels Set               | Set of label IDs on a person                                                                           | system                       | No                       |
| `label_categories`        | Label Categories         | Label category / grouping                                                                              | system                       | No                       |
| `mobile_prefix`           | Mobile Prefix            | Dial code / country prefix (not encrypted)                                                             | system                       | No                       |
| `mobile_number`           | Mobile Number            | Full mobile number (built-in person field)                                                             | system                       | No                       |
| `email_status`            | Email Status (State)     | Email deliverability/engagement state                                                                  | system                       | No                       |
| `sms_status`              | SMS Status (State)       | SMS deliverability/engagement state                                                                    | system                       | No                       |
| `whatsapp_status`         | WhatsApp Status (State)  | WhatsApp deliverability/engagement state                                                               | system                       | No                       |
| `email`                   | Email                    | Email address (built-in person field)                                                                  | system                       | No                       |
| `message`                 | Message                  | Message reference/content                                                                              | system                       | No                       |
| `engagement_tier`         | Engagement Tier          | Communication engagement tier                                                                          | system                       | No                       |
| `communication_frequency` | Communication Frequency  | Communication cadence                                                                                  | system                       | No                       |
| `channel`                 | Communication Channel    | Communication channel                                                                                  | system                       | No                       |
| `language`                | Language                 | ISO 639-1/639-2 code (built-in person field)                                                           | system                       | No                       |
| `source_type`             | Source Type              | Origin of a person or record, meaning how it was created. A built-in field, see [§6](#6-special-types) | system                       | No                       |

**A type that once existed and is gone:** an early `user` type, labelled "User Reference", left the catalogue and appears nowhere now.

Two notes on newer additions. `language` and `source_type` are system-scoped built-in person fields. `encrypted_string` carries the stack and person scopes. See [§5](#5-special-types).

***

## 3. Scopes: where a type shows up

Four scopes exist, and a type may carry several. The scope filters which types appear on each attribute-creation surface.

| Scope           | Governs                                                                                         | Surface                        |
| --------------- | ----------------------------------------------------------------------------------------------- | ------------------------------ |
| `stack`         | Types offered when defining a **stack attribute** (a record column)                             | Stack attribute form           |
| `person`        | Types offered when defining a **people attribute**                                              | People attribute form          |
| `custom-action` | Types offered for **custom-action** request/response parameters                                 | Custom-action attribute editor |
| `system`        | Internal types for built-in fields and derived state, **not** exposed in any attribute dropdown | ,                              |

Consequences worth knowing from the seed:

* The **person** scope is a subset of the **stack** scope. The relationship-to-people types, `person` and `people`, are **stack-only**. Point a stack record at a person freely. A person attribute can never take the type "Related Person". A person *can* reference a stack record, since the `stack` type sits in both scopes.
* The **custom-action** scope is the only home of the JSON container types: `object`, `array_objects`, `array_strings` and `array_integers`. They shape webhook payloads rather than storing values on people and records.
* `hour`, `select`, `multiselect`, `country`, `currency` and `stack` carry the stack and person scopes, and **not** custom-action.

***

## 4. Type → operators

Build a rule, filter, branch or segment, and the field's data type decides which comparison operators you get. Four operators take no comparison value: `empty`, `not_empty`, `true` and `false`.

This section maps types to operator groups. For what each operator **means**, with examples per data type, see [Rules & Operators](/docs/core-concepts/rules-and-operators.md).

| Operator group                                 | Operators offered                                                                                                              | Data types using it                                                                                                                                                                                          |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **String**                                     | is, is not, is empty, is not empty, contains, does not contain, begins with, does not begin with, ends with, does not end with | `string`, `encrypted_string` (and `email`/`mobile_number` when PII encryption is off, see below)                                                                                                             |
| **Integer** (numeric)                          | is, is not, greater, greater-or-equal, less-or-equal, less, is empty, is not empty, between, not between                       | `integer`, `float`                                                                                                                                                                                           |
| **Boolean**                                    | is true, is false, is empty, is not empty                                                                                      | `boolean`                                                                                                                                                                                                    |
| **Date**                                       | is, is not, is after, on-or-after, on-or-before, is before, between, not between, is empty, is not empty                       | `date`, `datetime`                                                                                                                                                                                           |
| **Select**                                     | is, is not, is empty, is not empty                                                                                             | `select`, `person`, `stack`, `currency`, `country`, `language`, `source_type`, `mobile_prefix`, `label_categories`, `channel`, `engagement_tier`, `communication_frequency`, `relationship` (frontend alias) |
| **Multi-select**                               | contains, does not contain, is empty, is not empty                                                                             | `multiselect`, `people`, `labels`                                                                                                                                                                            |
| **Time (hour/minute)**                         | is, is not, is after, on-or-after, on-or-before, is before, between, not between                                               | `hour`, `minute`                                                                                                                                                                                             |
| **Time-of-day / day / weekday / month / year** | subset of the above (equal/not-equal, or between) used for date-part comparisons                                               | `time_of_day`, `day`, `weekday`, `month`, `year`                                                                                                                                                             |

Data type drives two operator behaviours at a deeper level.

* **PII-aware operators.** On `email` and `mobile_number`, the builder offers **Select** operators, meaning equality alone, when PII encryption is on. It offers full **String** operators when encryption is off. Substring search cannot run over encrypted values. See [§5](#5-special-types).
* **`between` needs two values.** The builder renders `between` and `not_between` with a paired input, a from and a to.

The full operator vocabulary the platform understands is: `equal`, `not_equal`, `greater[_or_equal]`, `less[_or_equal]`, `between`, `not_between`, `contains`, `not_contains`, `begins_with`, `not_begins_with`, `ends_with`, `not_ends_with`, `empty`, `not_empty`, `true`, `false`.

***

## 5. Coercion & materialization

A rule or action field resolving at runtime has its operand value **coerced to the target data type and normalized** before any comparison or write. The automation engine applies the full mechanism during a run, covering operand kinds, the event map and fallbacks. Here is the type-relevant summary.

* **String trimming.** String values get trimmed on resolve, matching the trimming applied at write time, so a rule comparison and the stored value agree.
* **Person normalization.** A value targeting a `person` or `people` type gets wrapped as an identifier object: `{ internal_id: N }` for a numeric ID, or `{ external_id: "…" }` for a client string.
* **Record and stack normalization.** A value targeting a `stack` record reference gets wrapped as `{ record_id: "uuid" }` or `{ external_id: "…" }`.
* **Per-type value validation.** Each type enforces its shape. `hour` runs 0 to 23. `date` must parse as `YYYY-MM-DD`. `country`, `currency`, `language`, `mobile_number` and `mobile_prefix` must match their ISO or E.164 formats. Container types must hold non-empty arrays or objects.
* **Multi-value merge.** The multi-value types, meaning `people`, `multiselect`, `labels`, `array_strings`, `array_integers` and `array_objects`, support merge and remove semantics. They add to or remove from the existing set rather than replacing it.

***

## 6. Special types

**`encrypted_string`, PII encrypted at rest.** Values encrypt before storage and decrypt on read. The type carries the `stack` and `person` scopes, so either kind of attribute can take it.

The stored form is ciphertext, so equality and emptiness comparisons work over it and substring operators mean nothing. That is why the built-in encrypted person fields, `email` and `mobile_number`, switch to equality-only operators with encryption on. Encryption details such as keys, cipher and blind indexes are internal and sit outside this page.

**`source_type`, covering how an entity was created and what triggered an action.** One set of **nine values** plays a **dual role** in the platform.

*Role 1, creation origin.* Every person and every record carries a `source_type` recording **how that entity entered the system**. Flapjax writes it **once, at creation, and never updates it**. Treat it as a permanent provenance stamp.

| Value              | Display label    | Set when the entity was created by…                                                     |
| ------------------ | ---------------- | --------------------------------------------------------------------------------------- |
| `api`              | API              | A REST ingest call (public API)                                                         |
| `rabbitmq`         | RabbitMQ         | An AMQP / streaming ingest message                                                      |
| `manual`           | Manual           | A write in the web app (someone adding/editing directly)                                |
| `import`           | Import           | A CSV import                                                                            |
| `auto_created`     | Auto-Created     | An auto-created reference stub (a person/record materialized to satisfy a relationship) |
| `unsubscribe_page` | Unsubscribe Page | A consent write from the hosted unsubscribe page                                        |
| `automation`       | Automation       | An automation action writing the entity                                                 |
| `label_rule`       | Label Rule       | A label rule / recurring-label job assigning membership                                 |
| `callback_event`   | Callback Event   | A provider callback (delivery/engagement event from a channel provider)                 |

*Role 2, the run and send trigger.* The **same value set** lands on every automation action run and outbound send. There it records **what triggered that run or send**: an automation, a manual action, an API call, a callback and so on.

*Selectable and filterable are different things.* The catalogue above marks `source_type` **Selectable? No**, since it is system-scoped and you **cannot create a custom attribute of this type**.

Filtering is another matter. `source_type` **is** a built-in filterable field on the People grid and the Stacks and Records grid, offered with its nine named options and Select operators. It appears in the [§4](#4-type--operators) Select-operator listing as a *filterable built-in column*, rather than a type any attribute-creation dropdown offers.

For the user-facing surface, see [Source Type on people](/docs/your-data/people/browsing-people.md#source-type) and [Source Type on records](/docs/your-data/stacks/browsing-stacks.md#source-type).

**`language`, which drives localized&#x20;*****content*****&#x20;rather than the app's interface language.** It types the built-in person `language` field as an ISO 639-1 or 639-2 code. The person's value then selects **per-language email and content variants** at send time.

A localized field resolves the recipient's-language variant first, then an action default, then a fallback. That is *data localization* of the message body, and it differs from the backoffice application's own interface language. See the i18n and localization doc.

**The `*_status` state types: `email_status`, `sms_status` and `whatsapp_status`.** System-scoped, enum-like types carrying a channel's deliverability and engagement state for a person. Nobody selects them, and the builder surfaces them through their option lists.

**Communication state types: `engagement_tier`, `communication_frequency` and `channel`.** All system-scoped, each backed by a fixed option list the builder renders as a Select.

**Select and relationship types get configured, not merely typed.** On `select` and `multiselect`, the attribute's configuration holds the option list. On the relationship types `person`, `people` and `stack`, it holds the relation target, such as `{ relation_type: one|many, relation_stack_id }`, and the builder resolves the referenced records and people into the value picker. See [relationships](/docs/core-concepts/relationships.md) for the full reference model.

***

## 7. How types drive the variable picker

The data type chooses more than operators. It **filters which variables you can insert** into a field.

Configuring an action or rule value, the builder offers context variables whose type suits the target field, and renders matching value inputs: option dropdowns for selects, date pickers for dates, paired inputs for `between`. Each type draws on its own option source, whether labels, stacks, countries, currencies, channels or date-part value lists.

See [People filtering & segments](/docs/your-data/people/filtering-and-segments.md) for the builder walkthrough. The automation engine resolves your chosen variable to an operand at runtime.

***

## Related

* [People attributes](/docs/your-data/people/attributes.md) covers creating and managing person fields.
* [Relationships](/docs/core-concepts/relationships.md) covers the reference model behind the `person`, `people` and `stack` types.
* [Glossary → Attribute](/docs/start-here/key-concepts.md) gives one-line definitions.
* Context variables & fallbacks covers operand kinds, materialization and coercion.
* Rules & segment builder covers the interface consuming all of the above.
