> ## Documentation Index
> Fetch the complete documentation index at: https://docs.morf.health/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Transformation

> Shape, format, and combine data for use in action configuration — names, dates, URLs, nested fields, and conditional values.

This doc is for anyone configuring actions that send data to third-party tools like HubSpot, Healthie, or an email. These expressions control *what gets sent* — formatting names, dates, URLs, and other fields into what your team needs. To check out our existing destinations, see our [Integrations page](/docs/libraries/introduction).

***

## Build a display name from profile fields

***Use this when** you're sending a patient's name to a CRM and want it properly formatted — for example, as a HubSpot deal name or contact display name.*

Combine first and last name into a single formatted string.

**Start here — simple first + last name:**

```
get_current_property_value("first_name").optFlatMap(firstName,
  get_current_property_value("last_name").optMap(lastName,
    titleCase(string(firstName)) + " " + titleCase(string(lastName))
  )
)
```

**With a label suffix (e.g. for a HubSpot deal name):**

```
get_current_property_value("first_name").optFlatMap(firstName,
  get_current_property_value("last_name").optMap(lastName,
    titleCase(string(firstName)) + " " + titleCase(string(lastName)) + " Intake"
  )
)
```

**Advanced — with city and state:**

```
get_current_property_value("first_name").optFlatMap(firstName,
  get_current_property_value("last_name").optFlatMap(lastName,
    get_current_property_value("us_mailing_address").?city.optFlatMap(city,
      get_current_property_value("us_mailing_address").?state.optMap(state,
        titleCase(string(firstName)) + " " + titleCase(string(lastName)) + " " +
        titleCase(string(city)) + ", " + titleCase(string(state)) + " Intake"
      )
    )
  )
)
```

<Tip>
  `titleCase()` automatically capitalizes names correctly — so "jane smith" becomes "Jane Smith" regardless of how the patient typed it.
</Tip>

<Accordion title="Suggested Prompts for Flo AI">
  Use these sample prompts with Flo to generate a CEL expression that fits your goals.

  ```
  Build a deal name from the patient's first name, last name, city, and state.
  ```

  ```
  Combine first and last name into a single display name with title casing.
  ```
</Accordion>

***

## Format a date for display or integration input

***Use this when** you need to send a date to a third-party tool and it needs to be in a specific format — like showing a birthday in an email or setting a HubSpot close date.*

Many integrations (like HubSpot) require dates in specific formats. Use these expressions to convert stored dates.

**Start here — format a date for display in an email (MM/DD/YYYY):**

```
get_current_property_value("date_of_birth").optMap(d, formatDateUSStyle(d)).orValue("")
```

**Advanced — convert a future date to milliseconds for HubSpot:**

```
parseTimestamp(
  morf_event_time.add(parseDuration("720h")).getDateString() + "T00:00:00Z"
).getMilliseconds()
```

**Annotated breakdown:**

```
parseTimestamp(                                          // Parse the string back into a timestamp
  morf_event_time.add(parseDuration("720h"))            // Add 30 days (720h) to the event time
    .getDateString()                                     // Get just the date portion (YYYY-MM-DD)
  + "T00:00:00Z"                                        // Anchor to midnight UTC
).getMilliseconds()                                     // Convert to milliseconds for HubSpot
```

<Warning>
  **HubSpot date fields need a number, not a date string.** If you're writing to a HubSpot date property, make sure to add `.getMilliseconds()` at the end — otherwise HubSpot won't accept the value.
</Warning>

<Accordion title="Suggested Prompts for Flo AI">
  Use these sample prompts with Flo to generate a CEL expression that fits your goals.

  ```
  Set the HubSpot close date to 30 days from now.
  ```

  ```
  Format the patient's date of birth for display in an email.
  ```
</Accordion>

***

## Build a URL with a profile ID

***Use this when** you want to send a patient a personalized link — like a pre-filled intake form — that includes their unique ID.*

Append a patient's integration-specific ID to a base URL to generate a personalized link.

**Template:**

```
"[BASE URL]" + morf_profile_ids.[integration].id
```

**Examples:**

```
"https://your-form-url.io/to/abc123?_id=" + morf_profile_ids.feathery.id

"https://your-app.io/intake?form_id=" + morf_profile_ids.feathery.id
```

<Tip>
  Replace `feathery` with the integration name that holds the ID you need (e.g. `healthie`, `hubspot`). Check the profile IDs available in your event payload to see which ones are populated.
</Tip>

***

## Format a mailing address

***Use this when** you need to pass a patient's full address to a CRM or other tool as a single field.*

Combine address line 1 and line 2 into a single string, with a fallback to just line 1 if line 2 is empty.

**Example output:** `123 Main St, Apt 4B`

```
get_current_property_value("us_mailing_address").?address_1.optFlatMap(address_1,
  get_current_property_value("us_mailing_address").?address_2.optMap(address_2,
    address_1 + ", " + address_2
  )
).or(
  get_current_property_value("us_mailing_address").?address_1
)
```

**Annotated breakdown:**

```
get_current_property_value("us_mailing_address").?address_1   // Get address line 1
  .optFlatMap(address_1,                                       // If present, try to get line 2
    get_current_property_value("us_mailing_address").?address_2
      .optMap(address_2, address_1 + ", " + address_2)        // Combine both lines
  )
.or(                                                           // Fallback: just line 1 if no line 2
  get_current_property_value("us_mailing_address").?address_1
)
```

***

## Invert or remap a value

***Use this when** you need to flip a value before sending it — for example, converting an internal code into a human-readable label, or reversing a yes/no answer.*

Transform one value into another — for example, flipping a boolean string, or mapping an internal code to a display label.

**Show "Yes" or "No" instead of "true" or "false":**

```
answers.?consented_to_treatment.optMap(val,
  val == 'true' ? 'Yes' : 'No'
)
```

**Show a readable label instead of an internal code (e.g. "cash\_pay" → "Self Pay"):**

```
answers.?insurance_type.optMap(val,
  val == 'cash_pay' ? 'Self Pay' : val
)
```

<Accordion title="Suggested Prompts for Flo AI">
  Use these sample prompts with Flo to generate a CEL expression that fits your goals.

  ```
  If the patient answered 'true' for is_day_time_patient, output 'No', otherwise output 'Yes'.
  ```

  ```
  Map the internal value 'cash_pay' to the label 'Self Pay' before sending to HubSpot.
  ```

  ```
  If the patient's status is 'active', output 'Enrolled', otherwise output 'Not Enrolled'.
  ```
</Accordion>

***

## Access nested object fields

***Use this when** a profile property holds a complex object — like an insurance record or address — and you need to pull out one specific field from inside it.*

When a property stores a nested object (like an insurance record or address), navigate into it with `.?field`.

**Template:**

```
get_current_property_value("[PROPERTY]").?[NESTED FIELD]
```

**Examples:**

```
get_current_property_value("primary_insurance").?payer_name

get_current_property_value("us_mailing_address").?city

get_current_property_value("us_mailing_address").?state
```

**With a fallback if the field is empty:**

```
get_current_property_value("primary_insurance").?payer_name.orValue("unknown")
```

<Warning>
  **Use `.?field` not `.field` when navigating nested objects.** The `?` tells Morf to handle the case where the field might be missing. Without it, the workflow may fail if the nested field isn't there.
</Warning>

***

## Access the first item in a list

***Use this when** a field returns multiple values — like a multi-select answer or a list of associated records — and you only need the first one.*

When a field contains a list, use `[0]` to get the first item.

**Get the first selected value from a multi-select answer:**

```
answers.?Language_selector[0]
```

**Get the ID of the first associated record:**

```
associated_deals[0].id
```

<Tip>
  If the list might be empty, ask Flo to add a safety check — otherwise the expression may fail if there's nothing in the list.
</Tip>

***

## Build a computed identifier from multiple fields

***Use this when** you need to generate a unique value — like an email address or reference key — by combining several fields together.*

Construct a synthetic value (like an email or reference key) by concatenating multiple fields.

**Generate a unique email from name and DOB:**

```
properties[?"firstName"].optFlatMap(firstName,
  properties[?"lastName"].optFlatMap(lastName,
    properties[?"client_dob"].optMap(dob,
      firstName + lastName + dob + "@yourorg.io"
    )
  )
)
```

**Generate a unique company name with a random suffix:**

```
get_current_property_value("last_name").value() + " Fam " + randomNumbers(3)
```

<Tip>
  `randomNumbers(3)` adds a random 3-digit number at the end — useful when you need records to be unique but don't have a better identifier available.
</Tip>

***

## Ready to build?

<CardGroup cols={2}>
  <Card title="Open the Dashboard" icon="arrow-right" href="https://dashboard.morf.health">
    Start building your workflow now.
  </Card>

  <Card title="Talk to the Morf team" icon="calendar" href="https://calendly.com/d/cxbb-67s-ztb/morf-setup-call">
    Want a walkthrough or help getting started? Book a demo with us.
  </Card>
</CardGroup>

***

## Further reading

For the complete CEL function reference — including all available operators, string functions, date helpers, and optional chaining syntax — see the [CEL Reference](/docs/libraries/cel).
