Skip to main content

Overview

Workflows use parameters for inputs and context for passing data between blocks. This enables dynamic, reusable workflows that can process different data on each run.

Parameter Types

Workflow parameters are declared in workflow_definition.parameters and have two main categories:

1. Workflow Parameters (Inputs)

These are the values you pass when running a workflow. Each parameter requires:
  • key: The name used to reference this parameter
  • parameter_type: Always "workflow" for input parameters
  • workflow_parameter_type: The data type
parameters:
  - key: company_name
    parameter_type: workflow
    workflow_parameter_type: string
    description: Name of the company

  - key: start_date
    parameter_type: workflow
    workflow_parameter_type: string
    default_value: "2026-01-01"

  - key: recipient_emails
    parameter_type: workflow
    workflow_parameter_type: json
    description: Array of email addresses
Available workflow_parameter_type values:
TypeDescriptionExample Value
stringText value"John Smith"
integerWhole number42
floatDecimal number99.99
booleanTrue or falsetrue
jsonJSON object or array{"key": "value"} or ["a", "b"]
file_urlURL to a file"https://example.com/resume.pdf"
credential_idReference to stored credential"cred_abc123"

2. Context Parameters

Context parameters reference outputs from other parameters or blocks. Use parameter_type: "context":
parameters:
  - key: user_info
    parameter_type: workflow
    workflow_parameter_type: json

  - key: user_email
    parameter_type: context
    source_parameter_key: user_info.email
This extracts user_info.email and makes it available as {{user_email}}.

3. Output Parameters

Output parameters collect results from the workflow. Use parameter_type: "output":
parameters:
  - key: extracted_ein
    parameter_type: output
    description: The extracted EIN number from the confirmation page
Output parameters are populated by block outputs during execution.

Using Parameters in Blocks

Reference parameters using Jinja2 template syntax: {{ parameter_key }}.

Simple Reference

blocks:
  - label: navigate_to_portal
    block_type: goto_url
    url: "{{ portal_url }}"  # References the portal_url parameter

Nested Fields

Access nested fields with dot notation:
parameters:
  - key: company_info
    parameter_type: workflow
    workflow_parameter_type: json

blocks:
  - label: fill_form
    block_type: navigation
    url: "{{ application_url }}"
    navigation_goal: |
      Fill out the form with:
      - Company Name: {{ company_info.name }}
      - Tax ID: {{ company_info.tax_id }}
      - Address: {{ company_info.address.street }}
When running:
run = await client.run_workflow(
    workflow_id="wpid_123456789",
    parameters={
        "application_url": "https://example.com/apply",
        "company_info": {
            "name": "Acme Corp",
            "tax_id": "12-3456789",
            "address": {
                "street": "123 Main St"
            }
        }
    }
)

Array Iteration

Access array elements by index:
blocks:
  - label: process_first_item
    block_type: navigation
    url: "{{ items[0].url }}"
    navigation_goal: "Process {{ items[0].name }}"

Passing Data Between Blocks

Each block produces an output that becomes available to subsequent blocks. Reference block outputs using {{ label_output }}.

Basic Example

blocks:
  - label: extract_order_id
    block_type: extraction
    data_extraction_goal: Extract the order ID
    data_schema:
      type: object
      properties:
        order_id:
          type: string

  - label: download_invoice
    block_type: file_download
    url: "https://example.com/invoice/{{ extract_order_id_output.order_id }}"
    navigation_goal: Download the invoice PDF
The extract_order_id block produces:
{
  "order_id": "ORD-123456"
}
The download_invoice block accesses this as {{ extract_order_id_output.order_id }}.

Complex Data Flow

blocks:
  # Step 1: Parse resume
  - label: parse_resume
    block_type: file_url_parser
    file_url: "{{ resume_url }}"
    file_type: pdf
    json_schema:
      type: object
      properties:
        name:
          type: string
        email:
          type: string
        skills:
          type: array
          items:
            type: string

  # Step 2: Use parsed data in navigation
  - label: apply_to_job
    block_type: navigation
    url: "{{ job_url }}"
    navigation_goal: |
      Fill out the job application:
      - Full Name: {{ parse_resume_output.name }}
      - Email: {{ parse_resume_output.email }}
      - Skills: {{ parse_resume_output.skills | join(', ') }}

  # Step 3: Extract confirmation
  - label: extract_confirmation
    block_type: extraction
    data_extraction_goal: Extract the application ID and status
    data_schema:
      type: object
      properties:
        application_id:
          type: string
        status:
          type: string

  # Step 4: Send notification with all context
  - label: send_notification
    block_type: send_email
    smtp_host_secret_parameter_key: smtp_host
    smtp_port_secret_parameter_key: smtp_port
    smtp_username_secret_parameter_key: smtp_username
    smtp_password_secret_parameter_key: smtp_password
    sender: [email protected]
    recipients:
      - "{{ parse_resume_output.email }}"
    subject: "Job Application Submitted - {{ parse_resume_output.name }}"
    body: |
      Hi {{ parse_resume_output.name }},

      Your application has been submitted.

      Application ID: {{ extract_confirmation_output.application_id }}
      Status: {{ extract_confirmation_output.status }}
      Position: {{ job_url }}

      Thank you!

Parameter Scoping with parameter_keys

By default, blocks have access to all workflow parameters and previous block outputs. Use parameter_keys to explicitly declare which parameters a block can access:
parameters:
  - key: credentials
    parameter_type: workflow
    workflow_parameter_type: credential_id

  - key: search_term
    parameter_type: workflow
    workflow_parameter_type: string

blocks:
  - label: login
    block_type: login
    url: "https://example.com/login"
    parameter_keys:
      - credentials  # Only has access to credentials

  - label: search
    block_type: navigation
    navigation_goal: "Search for {{ search_term }}"
    parameter_keys:
      - search_term  # Only has access to search_term
This is useful for:
  • Security: Limit credential access to specific blocks
  • Clarity: Make dependencies explicit
  • Debugging: Easier to trace parameter usage

Loop Context

Inside a for_loop block, access the current iteration value using {{ nested_block_label.current_value }}.

Basic Loop

parameters:
  - key: order_ids
    parameter_type: workflow
    workflow_parameter_type: json

blocks:
  - label: download_invoices
    block_type: for_loop
    loop_over_parameter_key: order_ids
    loop_blocks:
      - label: download_invoice
        block_type: file_download
        url: "https://example.com/invoice/{{ download_invoice.current_value }}"
        navigation_goal: Download the invoice PDF
When running with order_ids: ["ORD-001", "ORD-002", "ORD-003"], the loop executes three times:
  • Iteration 1: {{ download_invoice.current_value }} = "ORD-001"
  • Iteration 2: {{ download_invoice.current_value }} = "ORD-002"
  • Iteration 3: {{ download_invoice.current_value }} = "ORD-003"

Loop Over Block Output

blocks:
  # Extract all product URLs
  - label: extract_products
    block_type: extraction
    url: "https://example.com/products"
    data_extraction_goal: Extract all product URLs
    data_schema:
      type: object
      properties:
        product_urls:
          type: array
          items:
            type: string

  # Loop over extracted URLs
  - label: scrape_products
    block_type: for_loop
    loop_over_parameter_key: extract_products_output.product_urls
    loop_blocks:
      - label: extract_product_details
        block_type: extraction
        url: "{{ extract_product_details.current_value }}"
        data_extraction_goal: Extract product name, price, and description
        data_schema:
          type: object
          properties:
            name:
              type: string
            price:
              type: number
            description:
              type: string
The scrape_products loop iterates over extract_products_output.product_urls and extracts details from each URL.

Nested Loops

blocks:
  - label: outer_loop
    block_type: for_loop
    loop_over_parameter_key: categories
    loop_blocks:
      - label: extract_items
        block_type: extraction
        url: "https://example.com/category/{{ extract_items.current_value }}"
        data_extraction_goal: Extract all item IDs
        data_schema:
          type: object
          properties:
            item_ids:
              type: array
              items:
                type: string

      - label: inner_loop
        block_type: for_loop
        loop_over_parameter_key: extract_items_output.item_ids
        loop_blocks:
          - label: process_item
            block_type: navigation
            url: "https://example.com/item/{{ process_item.current_value }}"
            navigation_goal: Add item to cart

Default Values

Provide default values for optional parameters:
parameters:
  - key: max_results
    parameter_type: workflow
    workflow_parameter_type: integer
    default_value: 10

  - key: include_archived
    parameter_type: workflow
    workflow_parameter_type: boolean
    default_value: false

  - key: notification_email
    parameter_type: workflow
    workflow_parameter_type: string
    default_value: "[email protected]"
When running without these parameters, the defaults are used:
run = await client.run_workflow(
    workflow_id="wpid_123456789",
    parameters={
        "search_term": "widgets"
        # max_results defaults to 10
        # include_archived defaults to false
        # notification_email defaults to [email protected]
    }
)

Jinja2 Filters

Use Jinja2 filters to transform data:

Join Array

navigation_goal: |
  Enter skills: {{ resume_output.skills | join(', ') }}
Input: ["Python", "JavaScript", "SQL"] Output: "Python, JavaScript, SQL"

Upper/Lower Case

navigation_goal: |
  Enter name: {{ user_name | upper }}
Input: "john smith" Output: "JOHN SMITH"

Length

navigation_goal: |
  There are {{ items | length }} items to process.
Input: [1, 2, 3, 4, 5] Output: "There are 5 items to process."

Default Value

navigation_goal: |
  Welcome {{ user_name | default('Guest') }}
If user_name is undefined or null, outputs "Welcome Guest".

Conditional Logic

Use conditional blocks to branch based on parameter values:
blocks:
  - label: check_account_type
    block_type: conditional
    branch_conditions:
      - criteria:
          criteria_type: jinja2_template
          expression: "{{ account_type == 'premium' }}"
        next_block_label: premium_flow
      - criteria:
          criteria_type: jinja2_template
          expression: "{{ account_type == 'basic' }}"
        next_block_label: basic_flow
      - is_default: true
        next_block_label: free_flow

  - label: premium_flow
    block_type: navigation
    navigation_goal: "Access premium features"

  - label: basic_flow
    block_type: navigation
    navigation_goal: "Access basic features"

  - label: free_flow
    block_type: navigation
    navigation_goal: "Access free features"

Best Practices

1. Use Descriptive Parameter Keys

# Bad
parameters:
  - key: p1
    parameter_type: workflow
    workflow_parameter_type: string

# Good
parameters:
  - key: vendor_portal_url
    parameter_type: workflow
    workflow_parameter_type: string
    description: URL to the vendor portal login page

2. Add Descriptions

parameters:
  - key: start_date
    parameter_type: workflow
    workflow_parameter_type: string
    description: Download invoices from this date forward (format: YYYY-MM-DD)

3. Use JSON Schema for Complex Data

Instead of multiple flat parameters, use a single JSON parameter with a schema:
# Instead of this:
parameters:
  - key: company_name
    parameter_type: workflow
    workflow_parameter_type: string
  - key: company_tax_id
    parameter_type: workflow
    workflow_parameter_type: string
  - key: company_address
    parameter_type: workflow
    workflow_parameter_type: string

# Do this:
parameters:
  - key: company_info
    parameter_type: workflow
    workflow_parameter_type: json
    description: |
      Company information object:
      {
        "name": "Acme Corp",
        "tax_id": "12-3456789",
        "address": "123 Main St"
      }

4. Validate Critical Parameters

Use validation blocks to check parameter values:
blocks:
  - label: validate_date_format
    block_type: validation
    complete_criterion: "{{ start_date | regex_match('^\\d{4}-\\d{2}-\\d{2}$') }}"
    terminate_criterion: "The start_date parameter is not in YYYY-MM-DD format"

5. Extract Complex Expressions to Code Blocks

For complex transformations, use code blocks:
blocks:
  - label: calculate_totals
    block_type: code
    parameter_keys:
      - line_items
    code: |
      subtotal = sum(item['price'] * item['quantity'] for item in line_items)
      tax = subtotal * 0.08
      total = subtotal + tax
      result = {
          "subtotal": subtotal,
          "tax": tax,
          "total": total
      }

  - label: send_invoice
    block_type: send_email
    subject: "Invoice Total: ${{ calculate_totals_output.total }}"
    body: |
      Subtotal: ${{ calculate_totals_output.subtotal }}
      Tax: ${{ calculate_totals_output.tax }}
      Total: ${{ calculate_totals_output.total }}

Common Patterns

Pattern 1: Parse File → Process Items

blocks:
  - label: parse_csv
    block_type: file_url_parser
    file_url: "{{ csv_url }}"
    file_type: csv

  - label: process_rows
    block_type: for_loop
    loop_over_parameter_key: parse_csv_output
    loop_blocks:
      - label: process_row
        block_type: navigation
        url: "{{ application_url }}"
        navigation_goal: |
          Submit form with:
          - Name: {{ process_row.current_value.name }}
          - Email: {{ process_row.current_value.email }}

Pattern 2: Extract → Validate → Branch

blocks:
  - label: extract_status
    block_type: extraction
    data_extraction_goal: Extract the order status
    data_schema:
      type: object
      properties:
        status:
          type: string

  - label: validate_status
    block_type: validation
    complete_criterion: "{{ extract_status_output.status in ['pending', 'processing', 'completed'] }}"
    terminate_criterion: "Invalid status"

  - label: branch_by_status
    block_type: conditional
    branch_conditions:
      - criteria:
          criteria_type: jinja2_template
          expression: "{{ extract_status_output.status == 'completed' }}"
        next_block_label: download_receipt
      - is_default: true
        next_block_label: wait_for_completion

Pattern 3: Multi-Source Data Aggregation

blocks:
  - label: extract_from_source_a
    block_type: extraction
    url: "{{ source_a_url }}"
    data_extraction_goal: Extract product data

  - label: extract_from_source_b
    block_type: extraction
    url: "{{ source_b_url }}"
    data_extraction_goal: Extract pricing data

  - label: combine_data
    block_type: code
    parameter_keys:
      - extract_from_source_a_output
      - extract_from_source_b_output
    code: |
      result = {
          "product": extract_from_source_a_output,
          "pricing": extract_from_source_b_output,
          "combined": {
              "name": extract_from_source_a_output.get("name"),
              "price": extract_from_source_b_output.get("price")
          }
      }

  - label: send_report
    block_type: http_request
    method: POST
    url: "{{ webhook_url }}"
    body: "{{ combine_data_output }}"

Next Steps

Workflow Blocks

Complete reference of all block types

Running Workflows

Execute workflows and retrieve results

Creating Workflows

Build workflows with SDK, API, or UI

Build docs developers (and LLMs) love