Integration Studio

Data Transformer

Map and reshape data between systems using a visual field mapper or JSONata expressions — no code required for standard transformations.

The Data Transformer at Integrations → Transformer provides a visual way to define data mappings between external payload formats and FlowOS table schemas (and vice versa). Use it to normalize inbound webhook data, reshape records before sending to an API, or convert between field naming conventions.

Transform Types

TypeDescription
Visual MapperDrag-and-drop field mapping with type coercion and static value injection.
JSONataFull JSONata query language for complex transformations, array operations, and conditionals.
JQjq filter syntax for JSON reshaping. Familiar to DevOps teams.
SDK ArtifactUse a custom Transform artifact for logic that visual or expression transforms cannot handle.

Visual Field Mapper

The visual mapper shows source fields on the left and target fields on the right. Draw a line between fields to create a mapping. Each mapping supports:

  • Direct copy — copy the value as-is.
  • Type coercion — string → number, number → string, epoch → ISO 8601, etc.
  • Static value — always write a fixed value regardless of input.
  • String template — compose a string from multiple fields: {{firstName}} {{lastName}}
  • Enumeration map — map input enum values to output enum values (e.g., "High" → "P1").
  • Condition — write to the target only if a condition is met.

JSONata Transforms

JSONata is a query and transformation language for JSON. The full specification is at jsonata.org. Below are the patterns most used in integration transforms:

Basic Field Mapping

javascript
/* Input: PagerDuty incident */
/* Output: FlowOS incident fields */
{
  "title":       payload.incident.title,
  "source":      "pagerduty",
  "external_id": payload.incident.id,
  "severity":    payload.incident.urgency = "high" ? "P1" : "P2",
  "status":      "open",
  "created_at":  $toMillis(payload.incident.created_at)
}

Array Operations

javascript
/* Map array of tags */
{
  "tags": payload.labels.name[],

  /* Filter and map */
  "high_priority_ids": payload.issues[priority = "high"].id,

  /* Flatten nested array */
  "all_assignees": payload.projects.issues.assignee.email
}

Conditional Logic

javascript
{
  "severity": $lookup({
    "p1": "P1", "critical": "P1",
    "p2": "P2", "high":     "P2",
    "p3": "P3", "medium":   "P3",
    "p4": "P4", "low":      "P4"
  }, $lowercase(payload.priority)),

  "assigned_team": payload.team_name != null
    ? payload.team_name
    : "unassigned"
}

JQ Transforms

bash
# Reshape a GitHub push event into an event bus payload
{
  repo:    .repository.name,
  branch:  (.ref | split("/") | last),
  pusher:  .pusher.name,
  commits: [.commits[] | { id: .id, message: .message }]
}

Testing Transforms

The transformer editor has a built-in test panel. Paste sample input JSON on the left, see the transformed output on the right. Errors are highlighted with line numbers.

bash
# Test via API
POST /api/v1/integrations/transformer/:id/test
Body: { "input": { /* sample payload */ } }
Response: { "output": { /* transformed result */ }, "errors": [] }

Using in Workflows

Add a Transform node to the canvas. Select a saved transformer or write an inline JSONata expression. The node's output is the transformed object, available to downstream nodes as {{nodes.transform-1.*}}.

Save transformers as named, versioned objects even if you only use them once — the test panel and version history make debugging much easier than inline node expressions.