HeadlessOps
Scripting Guide

Template Expressions

Dynamic value interpolation in integration.yaml using ${{ }} syntax

Template Expressions

Expressions are evaluated at runtime and interpolated into input field values in integration.yaml. Always use the ${{ ... }} syntax. Works identically in TypeScript and Python steps:

input:
  email: "${{ trigger.body.email }}"
  plan: "${{ trigger.query.plan }}"

Expression Reference

ExpressionResolves to
${{ trigger.body.field }}Field from the inbound trigger payload body (POST/PUT body or manual run payload)
${{ trigger.query.field }}URL query parameter from the inbound webhook request
${{ trigger.headers.x-api-key }}Inbound trigger request header
${{ steps.STEP_ID.output.field }}Output field from a previously completed step
${{ config.KEY }}Workspace config / environment variable named KEY
${{ error.message }}Error message (available in on_failure steps)
${{ error.step }}ID of the step that failed (available in on_failure steps)

Nested field access uses dot notation: ${{ trigger.body.deal.contact.email }}.

pinned-trigger-payload.json

This file pins a static trigger payload used instead of the live event during manual and test runs. It must mirror the exact runtime structure:

Webhook triggers

{
  "query": { "plan": "Growth", "hours": "10" },
  "body": {},
  "headers": {}
}

Common mistake: A flat object like { "plan": "Growth" } causes ${{ trigger.query.plan }} to resolve to empty because there is no query key. Fallback logic in step code (e.g. input.get('plan') or 'Growth') may silently mask this.

Manual triggers

{
  "email": "test@example.com",
  "plan": "Growth"
}

For manual triggers, the payload is injected directly as trigger.body.