# Payloads

How structured data flows between nodes in a workflow.

## What is a Payload?

A payload is a structured key-value dictionary that carries data between nodes. When a workflow executes, each node receives a payload from its upstream connection, processes it, and passes a modified payload downstream.

Payloads accumulate data as they flow through the chain. Each node can read existing variables, add new ones, or modify values. Nothing is lost between steps unless a node explicitly removes a key.

    {
      "filePath": "/Users/me/Documents/report.pdf",
      "fileName": "report.pdf",
      "fileSize": 245760,
      "changeType": "modified"
    }

## Triggers Create the Initial Payload

Every workflow begins with a trigger. When a trigger fires, it creates the initial payload populated with its output variables. Different triggers produce different variables. For example, a File Changed trigger outputs the file path, name, size, and the type of change that occurred.

Downstream nodes then build on this initial payload, adding their own output variables to the dictionary.

## Variable Interpolation

Any text field in a node configuration supports variable interpolation using double-brace syntax:

    {{variableName}}

At execution time, Watchflows replaces the placeholder with the current value from the payload. If the variable doesn't exist, the placeholder is replaced with an empty string.

### Nested Access

When a payload variable contains structured data (like a JSON object), use dot notation to access nested properties. A numeric segment indexes into a list — so `results.0.snippet` reaches the first item's `snippet`. An out-of-range index resolves to an empty value rather than erroring:

    {{response.data.name}}
    {{response.headers.content-type}}
    {{items.0.title}}
    {{results.0.snippet}}

Structured nodes keep their data structured. AI and Agent nodes that return JSON output, Apple Notes and Apple Reminders result lists, and API Request JSON responses all emit real navigable objects and arrays — not text that merely looks like JSON. That means you can reach into them directly with `{{key.field}}` and `{{key.0.field}}`, and use those nested values in conditions and other node configs. When you drop the whole object or array into a text field (like a notification body), it renders as JSON text, so existing text uses keep working. AI models often wrap their JSON in a markdown code fence (````json … ````); that fence is stripped automatically, so the output is still parsed into a navigable object. Plain prose or a bare number is left exactly as-is.

## Example: Payload Accumulation

Consider a workflow: File Changed trigger → Template transformer → Notification action. Here is what the payload looks like at each step.

### Step 1: File Changed Trigger

The trigger fires when a file is modified and creates the initial payload:

    {
      "filePath": "/Users/me/Downloads/photo.jpg",
      "fileName": "photo.jpg",
      "fileExtension": "jpg",
      "fileSize": 1048576,
      "changeType": "created"
    }

### Step 2: Template Transformer

The template is configured with: `New file: {{fileName}} ({{fileSize}} bytes)`

The template output is added to the payload. All original variables are preserved:

    {
      "filePath": "/Users/me/Downloads/photo.jpg",
      "fileName": "photo.jpg",
      "fileExtension": "jpg",
      "fileSize": 1048576,
      "changeType": "created",
      "output": "New file: photo.jpg (1048576 bytes)"
    }

### Step 3: Notification Action

The notification title is set to `{{output}}`, which resolves to the template's output. The full payload is still available:

    {
      "filePath": "/Users/me/Downloads/photo.jpg",
      "fileName": "photo.jpg",
      "fileExtension": "jpg",
      "fileSize": 1048576,
      "changeType": "created",
      "output": "New file: photo.jpg (1048576 bytes)"
    }

## Key Points

- Payloads are dictionaries of key-value pairs that accumulate as data flows through nodes.
- Use `{{variableName}}` in any text field to reference payload data.
- Dot notation like `{{response.data.name}}` accesses nested properties, and a numeric segment like `{{results.0.snippet}}` indexes into a list.
- Each node adds its output variables to the payload without removing existing ones.
- Missing variables resolve to an empty string at execution time.