> For the complete documentation index, see [llms.txt](https://docs.laminar.run/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.laminar.run/building-an-integration/integration-design/data-transformations.md).

# Data Transformations

Transforming data in Laminar

## Running data transformations

Laminar's [Lam Language](broken://pages/HKxG0mHw1Qa5maH9rRwF) is built entirely on top of [JQ](https://jqlang.github.io/jq/). Lam is run on each flow execution and is a JSON data transformation language that can support extremely complex conditional data transformations.

Data transformations access keys via `dot` notation and are able to reference data retrieved or transformed by previous flows in a workflow using the [Global Workflow Object](/building-an-integration/advanced/workflows/global-workflow-object.md).

<details>

<summary>View a simple JQ example</summary>

{% code lineNumbers="true" %}

```jq
# Remove some fields
.data | map(select(.value > 5))
```

{% endcode %}

</details>

<details>

<summary>View a complex JQ example</summary>

{% code overflow="wrap" lineNumbers="true" %}

```jq
# Define safe_notes with robust checking for nested structures
def safe_notes:
  if .step_1.response.notes then
    [.step_1.response.notes[] | select(.custom_types != null and any(.custom_types[]; .note_custom_value == "0 = \"DELIVERY_SUCCESSFUL\""))]
  else
    []
  end;

# Extract image URLs from notes that have them
def images:
  if .step_1.response.notes then
    [.step_1.response.notes[] | 
     select(.upload_url? and .upload_url != "") | 
     {url: .upload_url, extension: .upload_extension}]
  else
    []
  end;

# Evaluate the detailed_event and contents of notes
if (.input.detailed_event == "completed" and (safe_notes | length > 0)) then
  # Output for confirmed completed status with valid delivery success note and image URLs
  {
    "lam.resolveThenExecute": {
      "lam.workflowId": 55,
      "lam.payload": {
        "images": (images),
        "data": {
            "TrackingNumber": .input.address_custom_data.barcode,
            "ScanLatitude": .step_1.response.visited_lat,
            "ScanLongitude": .step_1.response.visited_lng,
        }
      },
      "lam.result": {}
    }
  }
elif (.input.detailed_event == "completed" and (safe_notes | length == 0)) or .input.detailed_event == "skipped" or .input.detailed_event == "failed" then
  # Output for delivery issues or no valid delivery success note found
  {
    "WS_Key": "..",
    "WSKeyLevel": "Carrier",
    "CarrierId": 10204,
    "TrackingNumber": .input.address_custom_data.barcode,
    "StartDate": (now | strflocaltime("%Y-%m-%dT%H:%M:%S")),
    "EndDate": (now + 86400 | strflocaltime("%Y-%m-%dT%H:%M:%S")),
    "TrackingInfo": {
      "EstimatedDeliveryDate": (now + 86400 | strflocaltime("%Y-%m-%dT%H:%M:%S")),
      "DeliveryDate": (now + 86400 | strflocaltime("%Y-%m-%dT%H:%M:%S")),
      "Event": {
        "ScanDateTime": (now | strflocaltime("%Y-%m-%dT%H:%M:%S")),
        "Status": "DeliveryException",
        "Description": "Exception occurred during delivery",
        "AlternateLanguageCode": "English",
        "ScanCountry": "CA",
        "ScanState": "ON",
        "ScanCity": "...",
        "ScanPostal": "..."
      },
      "PerformanceState": 0
    },
    "UpdateTrackingInfoShipmentLevel": true
  }
elif .input.detailed_event == "loaded" then
  # Output for 'loaded' status
  {
    "WS_Key": "...",
    "WSKeyLevel": "Carrier",
    "CarrierId": 10204,
    "TrackingNumber": .input.address_custom_data.barcode,
    "StartDate": (now | strflocaltime("%Y-%m-%dT%H:%M:%S")),
    "EndDate": (now + 86400 | strflocaltime("%Y-%m-%dT%H:%M:%S")),
    "TrackingInfo": {
      "EstimatedDeliveryDate": (now + 86400 | strflocaltime("%Y-%m-%dT%H:%M:%S")),
      "DeliveryDate": (now + 86400 | strflocaltime("%Y-%m-%dT%H:%M:%S")),
      "Event": {
        "ScanDateTime": (now | strflocaltime("%Y-%m-%dT%H:%M:%S")),
        "Status": "OutForDelivery",
        "Description": "Package is out for delivery",
        "AlternateLanguageCode": "English",
        "ScanCountry": "CA",
        "ScanState": "ON",
        "ScanCity": "...",
        "ScanPostal": "..."
      },
      "PerformanceState": 0
    },
    "UpdateTrackingInfoShipmentLevel": true
  }
else
  { "lam.exit": true }
end
```

{% endcode %}

</details>

## Invoking Laminar Keywords

Having a data transformation output one of the specified [Laminar Keywords](/building-an-integration/keywords.md) allows for more complex control flow logic to take place.

This is done by formatting the output in a way that is recognizable to the Laminar system as specified by the [Laminar Keywords](/building-an-integration/keywords.md).

```jq
.input |
if ((.activity_type == "route-destination-status" or
     .activity_type == "update-destinations") and
    (.detailed_event? | tostring | test("skipped|failed|completed|loaded")) and
    (.order_id | length > 0))
then
{
  "lam.resolveThenExecute": {
    "lam.workflowId": 60,
    "lam.payload": .,
    "lam.result": { "status": "OK" }
  }
}
else 
    { "lam.exit": true } 
end
```
