# Attribute Transformers

When creating workflows in Lifecycle Management policies to create, sync, or deprovision identities, you will use **attribute transformers** to specify how user attributes for target accounts should be structured.

{% hint style="info" %}
**Terminology:** For definitions of *transformer*, *formatter*, *pipeline function*, and *condition*, see [Understanding Conditions and Transformers](/4yItIzMvkpAvMVFAamTf/features/lifecycle-management/policies-workflows/conditions-and-transformers-overview.md#terminology).
{% endhint %}

An **attribute transformer** is the complete configuration for mapping a source attribute to a destination attribute. It consists of:

| Component                 | Description                                           | Example                                                                                                                                       |
| ------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Destination attribute** | The target attribute to set                           | `email`, `username`, `distinguished_name`                                                                                                     |
| **Formatter**             | The template that constructs the value                | See [Terminology](/4yItIzMvkpAvMVFAamTf/features/lifecycle-management/policies-workflows/conditions-and-transformers-overview.md#terminology) |
| **Continuous sync**       | Whether to update on existing users                   | Enabled/Disabled                                                                                                                              |
| **Fallback formatters**   | Alternative templates if the primary causes conflicts | `{first_name}.{last_name}1@company.com`                                                                                                       |

The target attributes to create or update are typically mapped and, optionally, transformed from user metadata in the source of identity, such as an identity provider, HR system, or CSV upload. Attributes can be synchronized once or kept continuously in sync as changes occur throughout the user's employment lifecycle.

{% hint style="info" %}
Attribute transformers are also available when mapping columns in [CSV Upload integrations](/4yItIzMvkpAvMVFAamTf/integrations/integrations/csv/csv-transformations.md). This enables you to combine columns, reformat dates, standardize case, and apply other transformations during CSV import—without requiring Lifecycle Management workflows.
{% endhint %}

For example, attribute mapping and transformation can be used across Joiner, Mover, and Leaver scenarios:

* **Joiner**: Set new Azure AD User Principal Name to `{source username}@your-email-domain.com`. This is an example of mapping multiple attributes and performing a transformation. More specifically, you use the attribute transformer to generate an email address for new joiners. Use the source username (`user_principal_name`) from the source of identity (Azure AD UPN) for the first part (user attribute), while your-email-domain.com is used for the last part (target attribute).
* **Mover**: Always update a user’s “Manager” and “Department” attributes in Okta to match the user’s manager and department in Workday, a source of identity, whenever a department change or other employee mobility event occurs. This is an example of attribute mapping with continuous synchronization.
* **Leaver**: Move a user’s Active Directory account to an Organizational Unit (OU) reserved for terminated accounts.

When synchronizing a user’s attributes, Veza may apply many transformations to convert the source attribute values into a more suitable format intended for the target application as a user account attribute.

For example, a transformer might remove the domain from an email address, replace special characters, or convert a string with uppercase letters to lowercase letters.

See [Attribute Synchronization](/4yItIzMvkpAvMVFAamTf/features/lifecycle-management/transformers/attribute-sync.md) for detailed information.

### Key Terminology

| Term                     | Description                                                          | Examples                                                                         |
| ------------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Source of Identity (SOI) | The system holding authoritative user data—the "source of truth"     | HR systems (Workday, BambooHR), identity providers (Azure AD, Okta), CSV uploads |
| Target Application       | The system where user accounts are created or updated using SOI data | Active Directory, Okta, Google Workspace, SaaS applications                      |

## Adding transformers

Common transformers define one or more rules to apply when synchronizing the attributes of a target identity. Use them at the Policy level where you want to create or update attributes using the same conventions across multiple sync or deprovision actions. When you need to configure a one-time individual action in a workflow, such as a specific attribute, then you use the transformer at the Action level.

At the Policy level, you configure a transformer with basic details, including how to source the value of each attribute:

1. Assign a name and description to the transformer, and specify the data source to which it applies.
2. **Entity Type**: Choose the target entity type in the destination system.
3. Click **Add Attribute**. The **Destination Attribute** dropdown will list available attributes for the chosen entity type.

   * **Destination Attribute**: Choose the attribute that Veza will create or update for the target entity.
   * **Formatter**: Choose how the destination attribute should be formatted. Specify the value, a `{source_attribute}`, or apply [Transformation Functions](#transformation-functions).
   * **Then Apply**: Chains transformation functions together using the pipe (`|`) character. Each function runs in sequence, with the output of one becoming the input of the next.

   See [Then Apply](#pipeline_functions_pipelinefunctions_474) for more examples.

   * **Continuous Sync**: Enabling this option ensures that the attribute is always synced, while applying any defined transformations. By default, attributes will not be synced if the target identity already exists.

After creating a common transformer, you can select it when editing a workflow action. You can edit or delete common transformers on the *Edit Policy* > *Common Transformers* tab.\
Remember that "Sync Identity" and "De-Provision Identity" actions can have action-level transformers override common transformers. If the same destination attribute is defined in both, the action-level transformer will take precedence.

## Best practices

### When to use common transformers

Create common transformers when the same transformation logic appears in two or more places within the policy. Common transformers reduce duplication and ensure consistent formatting across actions.

### When to use transformer functions

Create transformer functions when the same transformation applies to multiple properties. Functions let you reuse logic without duplicating configuration.

## Formatter syntax <a href="#formatters_95" id="formatters_95"></a>

The **Formatter** field in a transformer specifies how to construct the attribute value. It can be set to a specific value, synchronized with a source attribute, transformed using a function, or a combination of these.

{% hint style="info" %}
Some formatters should enable continuous synchronization for the attribute, while others should not. For example, the value of "Created By" should be immutable once a user account is provisioned. Other attributes that represent a state or status should be synchronized throughout the user's or account's lifecycle.
{% endhint %}

### **Simple Value Setting** <a href="#simple_value_setting_101" id="simple_value_setting_101"></a>

To create a destination attribute with a fixed value, enter the desired value when configuring the formatter.\
For setting the creator attribute:

| Destination Attribute | Formatter | Continuous Sync |
| --------------------- | --------- | --------------- |
| created\_by           | “Veza”    | Disabled        |

For activating a re-hired employee:

| Destination Attribute | Formatter | Continuous Sync |
| --------------------- | --------- | --------------- |
| isActive              | true      | Enabled         |

### **Empty Values** <a href="#empty_values_116" id="empty_values_116"></a>

To clear an attribute value, leave the formatter field empty. The behavior at the destination depends on system type:

* **SQL-based destinations** (Oracle, MySQL, MSSQL): an empty formatter sends `NULL` to the database column.
* **SCIM destinations**: an empty formatter sends an empty string to the provider.

For deactivating a user or clearing a manager reference:

| Destination Attribute | Formatter | Continuous Sync |
| --------------------- | --------- | --------------- |
| manager\_id           | *(empty)* | Enabled         |
| isActive              | false     | Enabled         |

{% hint style="info" %}
Attributes marked as required or configured as unique identifiers cannot have an empty formatter — the policy will not save until a value is provided for those fields.
{% endhint %}

{% hint style="warning" %}
Do not use a space character to represent an empty value. The formatter field trims leading and trailing whitespace on input, so a space is equivalent to leaving the field blank.
{% endhint %}

### **Attribute references** <a href="#source_of_identity_formatters_125" id="source_of_identity_formatters_125"></a>

Target attributes can be updated based on attributes belonging to the source of identity. To reference the value of a source entity attribute in your formatter, use the format `{<source_attribute_name>}`.

Examples:

| Destination Attribute | Formatter Example                                                                                                                                                                                                                                                                                          | Continuous Sync |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| first\_name           | `{first_name}`                                                                                                                                                                                                                                                                                             | Enabled         |
| last\_name            | `{last_name}`                                                                                                                                                                                                                                                                                              | Enabled         |
| email                 | `{first_name}.{last_name}@domain.com` `{first_name}_{last_name}@domain.com` `{last_name}@domain.com` `{firstname_initial}{last_name}@domain.com` `{firstname_initial}-{last_name}@domain.com` `{firstname_initial}{middlename_initial}{last_name}@domain.com` `{last_name}-{firstname_initial}@domain.com` | -               |

### Alias Definitions

{% hint style="info" %}
**Early Access:** Alias Definitions is currently in early access. Contact your Veza representative to enable this feature for your tenant.
{% endhint %}

#### When to use aliases

By default, when you reference an attribute such as `{department}` in a formatter, the system searches through your configured identity sources in order (primary first, then secondary sources). This works well for simple policies with a single source of identity.

Aliases become useful when:

* **Multiple integrations share the same entity type** (e.g., two Active Directory instances, or when your source of identity and sync target use the same entity type)
* A policy involves **multiple integrations** that have attributes with the same name
* You need to **explicitly control** which system's attribute value is used
* You want to **compare values** between source and target systems while defining LCM Workflow Conditions
* You need to detect **movers** based on changes in a specific system

{% hint style="info" %}
**Alias Naming**: The system automatically adds a `$` prefix to all alias names. For example, if you create an alias named `workday` in the UI, it becomes `$workday` when used in formatters and conditions.
{% endhint %}

**Example: HR System to Directory Sync**

A policy syncs identities from an HR system (Workday) to a directory (Active Directory). Both have a `department` attribute. Without aliases, `{department}` resolves from whichever system appears first in the search order. With configured aliases `hr` and `directory` (which become `$hr` and `$directory`), you can explicitly reference `{$hr.department}` to ensure you're using the authoritative HR value.

Aliases can be used in:

* Attribute formatters
* Workflow trigger conditions
* Action conditions
* Mover property definitions
* Test formatters (for validation before deployment)

#### Configuring aliases

Aliases provide shorthand references to specific integrations and entity types, making transformers and conditions more readable in complex policies.

To configure aliases, open a Lifecycle Management policy, click **Edit**, and navigate to the **Alias Definitions** tab. Each alias requires:

* **Alias Name**: Must start with `$` followed by at least one lowercase letter, number, or underscore. Additional `$` characters can appear after the first character. The `$` prefix is added automatically if omitted. Valid examples: `$workday`, `$hr_system`, `$ad$corp`. Invalid examples: `$`, `$AD` (uppercase), `$$double` (multiple leading `$`).
* **Integration**: The data source containing the entity type.
* **Entity Type**: The entity type to reference (e.g., `WorkdayWorker`, `OktaUser`).

{% hint style="warning" %}
**Validation Rules**: Alias names allow only lowercase alphanumeric characters, underscores, and `$`. They must start with exactly one `$` (not zero, not multiple), and cannot be `$target` (reserved for action-level attribute references).
{% endhint %}

{% hint style="success" %}
**Testing and Validation**: Aliases work in test formatters, allowing you to validate your formatter expressions before deployment. Additionally, alias-resolved attribute values appear in dry run results, so you can preview exactly which values will be synced.
{% endhint %}

#### Input and output resolution

Aliases can resolve attributes from two contexts:

* **Input**: Values from the source system before any sync action runs (the authoritative data)
* **Output**: Values currently in the target system (what's already provisioned)

By default, the system checks output first, then falls back to input. Use suffixes to explicitly control resolution:

| Suffix   | Resolves From      | Example                     | Use Case                           |
| -------- | ------------------ | --------------------------- | ---------------------------------- |
| *(none)* | Output, then input | `{$workday.department}`     | General attribute access           |
| `$in`    | Source only        | `{$workday$in.department}`  | Get the authoritative source value |
| `$out`   | Target only        | `{$workday$out.department}` | Get the current target value       |

{% hint style="info" %}
**When to Use Suffixes**: Use `$in` when you need the authoritative value from the source system (e.g., HR system). Use `$out` when you need to compare against what's currently provisioned in the target. Without a suffix, the system checks the target first—useful when you want the most recent value regardless of source.
{% endhint %}

#### Comparison operators

Use these operators in `IF` conditions to compare attribute values:

| Operator | Meaning                | Supported Types                    |
| -------- | ---------------------- | ---------------------------------- |
| `eq`     | Equals                 | Boolean, string, number, timestamp |
| `ne`     | Not equals             | Boolean, string, number, timestamp |
| `co`     | Contains               | String, string list                |
| `sw`     | Starts with            | String                             |
| `ew`     | Ends with              | String                             |
| `lt`     | Less than              | Number, timestamp                  |
| `le`     | Less than or equals    | Number, timestamp                  |
| `gt`     | Greater than           | Number, timestamp                  |
| `ge`     | Greater than or equals | Number, timestamp                  |

Combine conditions with `and`, `or`, or negate with `not`.

{% hint style="info" %}
**String List Attributes**: For multi-value attributes (string lists), only the `co` (contains) operator is supported. Use it to check if the list includes a specific value, for example: `IF $workday.roles co "Manager"`.
{% endhint %}

#### Examples

**In attribute formatters:**

```txt
{$workday.first_name | LOWER}.{$workday.last_name | LOWER}@company.com
```

**In LCM Workflow Conditions (comparing source and target values):**

```txt
IF $workday$in.department ne $ad$out.department
  {$workday$in.department}
ELSE
  {$ad$out.department}
```

**Multiple integrations with the same entity type:**

For organizations with multiple Active Directory domains (e.g., corporate employees and contractors), you can create distinct aliases to control which AD integration is used:

* Configure alias `corp_ad` → Integration: AD\_Corporate, Entity Type: ActiveDirectoryUser
* Configure alias `contractor_ad` → Integration: AD\_Contractors, Entity Type: ActiveDirectoryUser

Then explicitly reference the correct domain in your formatters:

```txt
{$corp_ad.department}
```

This ensures you're using the `department` attribute from the corporate AD integration rather than the contractor AD integration, even though both use the same `ActiveDirectoryUser` entity type.

### **Transformation functions** <a href="#transformation_functions_136" id="transformation_functions_136"></a>

Based on the user metadata available from your source of identity (SOI), you may need to convert a full email address to a valid username, standardize a date, or generate a unique identifier for users provisioned by Veza. Suppose an attribute value needs to be altered to be compatible with the target system. In that case, you can transform the value of a source attribute or apply a range of other functions to generate the target value.

Formatter expressions use the following syntax: `{<source_attribute_name> | <FUNCTION_NAME>,<param1>,<param2>}`

For example:

<table><thead><tr><th width="186.9140625">Destination Attribute</th><th width="117.45703125">Formatter</th><th width="155.66796875">Description</th><th>Example</th></tr></thead><tbody><tr><td>username</td><td>`{email | REMOVE_DOMAIN}`</td><td>Removes the domain from the email to create username</td><td>"jsmith" is the output derived from jsmith@company.com</td></tr><tr><td>user_id</td><td>`f{id | UPPER}`</td><td>Converts ID to uppercase</td><td>JSMITH" is the output derived from the userid, "jsmith"</td></tr></tbody></table>

### Transformation function categories

Refer to the [Transformer Reference](/4yItIzMvkpAvMVFAamTf/features/lifecycle-management/transformers/transformer-reference.md) page for complete documentation of all supported functions, parameters, and usage examples. The reference includes:

| Category                | Functions                                                                                                                             | Use Cases                                    |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| **String case**         | UPPER, LOWER, TITLE\_CASE, SENTENCE\_CASE, LOWER\_CAMEL\_CASE, UPPER\_CAMEL\_CASE, LOWER\_SNAKE\_CASE, UPPER\_SNAKE\_CASE             | Standardize naming conventions               |
| **String manipulation** | TRIM, TRIM\_CHARS, REMOVE\_CHARS, REMOVE\_WHITESPACE, REPLACE\_ALL, APPEND, PREPEND                                                   | Clean and format string data                 |
| **Substring**           | FIRST\_N, LAST\_N, SUB\_STRING, SPLIT                                                                                                 | Extract portions of values                   |
| **Padding**             | LEFT\_PAD, RIGHT\_PAD, ZERO\_PAD                                                                                                      | Create fixed-width identifiers               |
| **Date/time**           | DATE\_FORMAT, DATE\_ADJUST, DATE\_ADJUST\_DAY, ASSUME\_TIME\_ZONE, UTC\_TO\_TIME\_ZONE, NOW                                           | Convert and manipulate dates                 |
| **Character encoding**  | ASCII, REMOVE\_DIACRITICS                                                                                                             | Handle international characters              |
| **Lookup**              | LOOKUP, FROM\_ENTITY\_ATTRIBUTE, FROM\_MANY\_ENTITIES\_ATTRIBUTE                                                                      | Cross-reference data from tables or entities |
| **Generation**          | NEXT\_NUMBER, UUID\_GENERATOR, RANDOM\_INTEGER, RANDOM\_STRING\_GENERATOR, RANDOM\_ALPHANUMERIC\_GENERATOR, RANDOM\_NUMBER\_GENERATOR | Create unique values                         |
| **Domain**              | REMOVE\_DOMAIN                                                                                                                        | Extract usernames from email addresses       |
| **Formatting**          | COUNTRY\_CODE\_ISO3166, LANGUAGE\_RFC5646, PHONE\_NUMBER\_E164                                                                        | Standardize to international formats         |

{% hint style="info" %}
Contact Veza if you require additional transformations for your use case.
{% endhint %}

### **Then Apply** {#then-apply} <a href="#pipeline_functions_pipelinefunctions_474" id="pipeline_functions_pipelinefunctions_474"></a>

You can pipeline multiple transformation functions together, separated by a vertical bar (|). Each will apply in sequence, allowing for complex attribute formatters that use the output of one function as the input of another.

#### **Example Then Apply** <a href="#example_pipeline_functions_478" id="example_pipeline_functions_478"></a>

* `{name | UPPER}`
  * If name = Smith, the result is SMITH.
* `{first_name | SUB_STRING,0,1 | LOWER}.{last_name | LOWER}`
  * If first\_name = John and last\_name = Smith, the result is j.smith.
* `{email | REMOVE_DOMAIN}`
  * If email = `john.smith@domain.com`, the result is `john.smith`.
* `{email | REPLACE_ALL, " ", "."}`
  * If email = `john smith@domain.com`, the result is `john.smith@domain.com`.
* `{location | LOOKUP locationTable, location_code, city}`
  * If location = IL001, the result is Chicago (using a lookup table named locationTable).
* `{start_date | DATE_FORMAT, "01/02/2006" | UPPER}`
  * If start\_date = 2023-03-15, the result is 03/15/2023 (DATE\_FORMAT doesn't typically need UPPER, but shows pipeline capability).
* `{hire_date | DATE_FORMAT, "Jan 2, 2006" | REPLACE_ALL, " ", "_"}`
  * If hire\_date = 2023-03-15, the result is Mar\_15,\_2023.
* `{office_code | TRIM_CHARS_LEFT, ".0" | TRIM_CHARS_RIGHT, ".USCA"}`
  * If office\_code = 000.8675309.USCA, the result is 8675309.
* `{username | REMOVE_CHARS, ".-_" | TRIM | UPPER}`
  * If username = "–john.doe\_–", the result is JOHNDOE.
* `{employee_id | REMOVE_CHARS, "#" | TRIM_CHARS, "0" | LEFT_PAD, 6, "0"}`
  * If employee\_id = "##001234##", the result is 001234.
* `{department | REMOVE_WHITESPACE | LOWER | REPLACE_ALL, "&", "and"}`
  * If department = "Sales & Marketing", the result is salesandmarketing.
* `TEST{| RANDOM_INTEGER, 1000, 9999}`
  * Generates test IDs like TEST4827, TEST8391 (see [RANDOM\_INTEGER](/4yItIzMvkpAvMVFAamTf/features/lifecycle-management/transformers/transformer-reference.md) for details).

## Testing Transformers Inline

Before deploying transformers in production policies, you can validate formatter expressions directly in the Veza UI. This allows you to verify that your transformation logic produces the expected output without affecting live data.

### Using the Test Interface

When adding or editing a transformer in a policy, look for the **Test Formatter** button next to the transformer field. Clicking it opens a test dialog:

1. **Enter your transformer expression** in the Attribute Transformer field
2. Click the **Test Formatter** button to open the test dialog
3. The dialog shows input fields for each attribute referenced in your expression (e.g., `{first_name}`, `{email}`)
4. **Enter sample values** for each attribute
5. Click **Test Formatter** in the dialog to evaluate the expression
6. **View the result** to verify the transformation produces expected output
7. Click **Save** to close the dialog, or **Cancel** to discard changes

The test dialog is available wherever transformers are configured, including:

* Action synced attributes
* Unique identifiers
* Common transformers
* Date formatters

### Testing Examples

| Expression                                  | Test Input             | Expected Output |
| ------------------------------------------- | ---------------------- | --------------- |
| `UPPER`                                     | `john.doe`             | `JOHN.DOE`      |
| `{email \| SPLIT("@") \| INDEX(0)}`         | `john.doe@example.com` | `john.doe`      |
| `{start_date \| DATE_FORMAT("2006-01-02")}` | `2025-01-15T10:30:00Z` | `2025-01-15`    |
| `{name \| LOWER \| REPLACE_ALL(" ", ".")}`  | `John Smith`           | `john.smith`    |

### Testing Then Apply

For complex pipelines, test incrementally:

1. Test the first function alone to verify it handles the input correctly
2. Add each subsequent pipe and verify intermediate results
3. Validate the complete pipeline produces the final expected value

This step-by-step approach helps isolate issues when a transformation doesn't produce the expected output.

{% hint style="warning" %}
The test interface uses sample data you provide. Ensure your test values accurately represent the source attribute data types and formats you'll encounter in production.
{% endhint %}

### When to Use Inline Testing vs. Dry Run

| Scenario                                            | Use                                                                                                 |
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Validating a single transformer expression          | Inline Testing                                                                                      |
| Testing how transformers work with real entity data | [Dry Run](/4yItIzMvkpAvMVFAamTf/features/lifecycle-management/how-to/test-policies-with-dry-run.md) |
| Verifying complete policy workflow execution        | [Dry Run](/4yItIzMvkpAvMVFAamTf/features/lifecycle-management/how-to/test-policies-with-dry-run.md) |

Use inline testing during transformer development, then validate the complete policy with a dry run before deploying to production.

#### Common Transformers

As part of implementing Lifecycle Management (LCM) processes with Veza, you should create sets of common transformers to define how values such as username, login, or ID are sourced for each LCM Policy. These transformers can then be reused across all identity sync and deprovision policy workflows.

{% hint style="info" %}
Create common transformers to consistently form attributes for specific entity types, and reuse them to avoid errors and save time when creating actions for that entity type. The order of common transformers matters when multiple transformers set the same destination attribute. Drag-and-drop to reorder common transformers and control precedence.
{% endhint %}

For example, defining a common synced attribute to describe how to format Azure AD account names {username}@evergreentrucks.com enables reuse across multiple workflow actions. You can also define synced attributes at the action level when they are used only once within a policy, such as setting the primary group DN and OU of de-provisioned identities to a group reserved for terminated accounts.

**Common Transformer Examples:**

| Transformer & Entity Type                          | Attribute             | Value Format                                                                     | Continuous Sync | Description        |
| -------------------------------------------------- | --------------------- | -------------------------------------------------------------------------------- | --------------- | ------------------ |
| **ADAccountTransformer** *ActiveDirectoryUser*     | account\_name         | `{display_full_name}`                                                            | No              | Basic account name |
|                                                    | distinguished\_name   | `CN={first_name} {last_name},OU={department},OU={location},DC=company,DC=local`  | Yes             | Full AD path       |
|                                                    | user\_principal\_name | \`{first\_name                                                                   | SUB\_STRING,0,1 | LOWER}.{last\_name |
|                                                    | email                 | `{first_name}{last_name}@company.com`                                            | Yes             | Email address      |
| **OktaAccountTransformer** *OktaUser*              | login                 | \`{first\_name                                                                   | SUB\_STRING,0,1 | LOWER}.{last\_name |
|                                                    | email                 | `{first_name}{last_name}@company.com`                                            | Yes             | Email address      |
|                                                    | username\_prefix      | \`{first\_name                                                                   | SUB\_STRING,0,1 | LOWER}.{last\_name |
| **AzureADTransformer** *AzureADUser*               | principal\_name       | `{first_name}{last_name}`                                                        | No              | Primary identifier |
|                                                    | mail\_nickname        | \`{first\_name                                                                   | SUB\_STRING,0,1 | LOWER}{last\_name  |
|                                                    | display\_name         | `{first_name} {last_name}`                                                       | Yes             | Display name       |
| **GoogleAccountTransformer** *GoogleWorkspaceUser* | email                 | `{first_name}{last_name}@company.com`                                            | No              | Primary email      |
|                                                    | email\_addresses      | `{username}@company.com`                                                         | No              | Email list         |
|                                                    | recovery\_email       | `{personal_email}`                                                               | Yes             | Backup email       |
| **ContractorTransformer** *ActiveDirectoryUser*    | account\_name         | `c-{username}`                                                                   | No              | Contractor prefix  |
|                                                    | distinguished\_name   | `CN={first_name} {last_name},OU=Contractors,OU={department},DC=company,DC=local` | Yes             | Contractor OU      |
|                                                    | description           | `Contractor - {vendor_company} - Start Date: {start_date}`                       | Yes             | Metadata           |
| **RegionalEmailTransformer** *ExchangeUser*        | email\_address        | `{username}@{region}.company.com`                                                | No              | Regional email     |
|                                                    | alias                 | `{first_name}.{last_name}@{region}.company.com`                                  | Yes             | Regional alias     |

### **$target Attribute Transformer Function** <a href="#target_attribute_transformer_function_537" id="target_attribute_transformer_function_537"></a>

The $target attribute transformer function is used when a value consists of one or more attributes that require an operation(s), making it too complex to transform, but it needs to be reused.

{% hint style="warning" %}
**Important:** The $target function can only be used within the same Action.
{% endhint %}

For example, an email address consists of <firstname_lastname@sample.com>. However, you must use the format <username@sample.com>. By using the $target function, you reuse only one attribute, **username**, while not changing the other two attributes (firstname\_lastname).

**Example:**

**Destination Attribute**

```
username
```

**Formatter**

```
`{firstname}{lastname}`
```

**Formatter**

```
`{$target.username}@sample.com`
```

### Using Transformed Attributes as Lookup Keys

You can reference an attribute set by an earlier transformer as the lookup key in a subsequent transformer. This enables multi-stage transformation pipelines where one transformer computes a normalized value, and a later transformer uses that value for table lookups or other operations.

**Example:** Compute a padded employee ID in one transformer, then use it to look up a cost center in a later transformer:

Transformer 1 — set `padded_id`:

```
{employee_id | LEFT_PAD, 8, "0"}
```

Transformer 2 — use `padded_id` as the lookup key:

```
{$target.padded_id | LOOKUP costCenterTable, padded_id, cost_center}
```

The `$target.padded_id` reference resolves to the value set by Transformer 1, and passes it as the key into the LOOKUP function.

{% hint style="info" %}
**Order matters:** Transformers run in the order they are defined. Place the transformer that sets the source attribute before any transformer that references it via `$target`.
{% endhint %}

### **Custom Attribute Transformer Function** <a href="#custom_attribute_transformer_function_565" id="custom_attribute_transformer_function_565"></a>

The Custom Attribute Transformer function allows you to define a custom transformer that acts as an alias for applying one or more transformer functions.

For example, you can define a custom function named `$CLEAN`, which is used as `{first_name | $CLEAN}`. This function can consist of a series of transformer functions such as `| ASCII | LOWER | REMOVE_CHAR |`.

To define a custom attribute transformer, use the following guidelines:

**Policy Version Definitions**

* Custom functions must be defined as part of the policy version.
* These definitions are structured similarly to hard-coded definitions and are returned in the same format, allowing the Veza UI to handle them without modification.
* The API for updating and retrieving a policy version must also support these custom function definitions.

{% hint style="info" %}
**Naming Convention:** Custom functions must be in **ALL CAPS** and prefixed with a $ to avoid conflicts with built-in functions.
{% endhint %}

**Custom Attribute Transformer Limitations**

The following custom definitions are not supported:

* Transformer functions with included transformer parameters
* Nested transformer functions
* Transformer functions with parameters

### **Appending Multi-Value Attribute (Active Directory only)**

As part of the Identity Sync action, you can append values to multi-value Active Directory attributes without replacing existing values. This ensures that existing attribute values are preserved when adding new ones.

{% hint style="info" %}
This feature is specific to Active Directory and is not available for other integrations.
{% endhint %}

**Supported Multi-Value Attributes:**

Active Directory supports appending for the following multi-value attributes:

* `organizationalStatus`, `departmentNumber`, `employeeType`
* `servicePrincipalName`, `proxyAddresses`
* `member`, `memberOf`, `roleOccupant`
* `url`, `wWWHomePage`
* `otherTelephone`, `otherMobile`, `otherIpPhone`, `otherFacsimileTelephoneNumber`, `otherHomePhone`, `otherPager`, `otherMailbox`
* And additional multi-value attributes including: `objectClass`, `postalAddress`, `postOfficeBox`, `seeAlso`, `userCertificate`, `userSMIMECertificate`, `userPKCS12`, `securityIdentifierHistory`, `altSecurityIdentities`, `businessCategory`, `carLicense`, `homePostalAddress`

**Syntax:**

Use the `>>` prefix before the array to append values:

```txt
>>[value1, value2, value3]
```

Appending syntax supports two array formats:

* **With quotes** (JSON format): `>>[``"Active", "Permanent"]`
* **Without quotes** (simple format): `>>[Active, Permanent]`

When you use this syntax:

1. New values are added to the end of the existing attribute values
2. Duplicate values are automatically removed
3. The order of existing values is preserved
4. New values appear after existing values in the order specified

For example, ff an Active Directory user has:

```txt
organizationalStatus: ["Active", "Employee"]
```

And you apply the transformer:

```txt
>>[Employee, Contractor, Temporary]
```

The resulting value is:

```txt
organizationalStatus: ["Active", "Employee", "Contractor", "Temporary"]
```

Note that "Employee" was already present and not duplicated.

**Setting vs. Appending:**

* To **Replace existing values**: Use `[value1, value2]` (without `>>`)
* To **Append to existing values**: Use `>>[value1, value2]` (with `>>`)

**Additional Notes:**

* The append prefix (`>>`) only works for multi-value attributes. It is ignored for single-value attributes
* If the attribute has no existing values, the values are simply set (no difference from non-append behavior)
* Both the appending syntax and the standard array syntax support arrays with or without quotes around values


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.veza.com/4yItIzMvkpAvMVFAamTf/features/lifecycle-management/transformers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
