Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.spojit.com/llms.txt

Use this file to discover all available pages before exploring further.

Every node in a workflow can reference data produced by earlier steps. You do this with template expressions — double-curly-brace placeholders like {{ something }} — anywhere in a node’s configuration (prompts, headers, body, connector arguments, etc.). This page covers:
  • The two data sources: the trigger payload and step outputs
  • How to name a step’s output so other nodes can reference it
  • Type preservation vs string interpolation
  • Common pitfalls

The two data sources

There are only two things you can reference from a template expression.

1. The trigger payload — {{ input }}

Whatever data started the workflow is available under the name input. This is:
  • The webhook body, for webhook-triggered runs
  • The input data you pass to a manual run
  • (Soon) the context object for scheduled runs
Example — a webhook sends:
{
  "customer_id": "cus_123",
  "order": { "total": 99.99, "currency": "USD" }
}
Inside any node, you can reference:
  • {{ input.customer_id }}"cus_123"
  • {{ input.order.total }}99.99
  • {{ input }} → the whole object

2. Previous step outputs

Any node upstream of the current one (connected via the graph) can expose its output to downstream nodes — but only if you give the step an output variable name in its properties panel. If you don’t set an output variable, the step’s result is still computed but it’s stored under a hard-to-use autogenerated name. Always set an output variable when a downstream node needs to reference the result.

Setting an output variable

  1. Click the node whose output you want to reference
  2. Find the Output Variable field in its properties panel (all node types that produce output have this)
  3. Enter a readable identifier — e.g. user_lookup, agent_result, parsed_csv
  4. In a downstream node, reference it: {{ user_lookup }}, {{ agent_result }}, {{ user_lookup.id }}, etc.
Use snake_case or camelCase — just letters, digits, and underscores. Avoid spaces, hyphens, and special characters.

What’s inside a step output

The shape depends on the node type. The most common ones:

AI Agent (Connector node in Agent mode)

The bound value is the agent’s primary output:
  • Without a Response Schema{{ agent_result }} is the AI’s text answer (a string).
  • With a Response Schema{{ agent_result }} is the structured object the schema defined; address fields directly: {{ agent_result.userName }}, {{ agent_result.items[0].id }}, etc.

Connector in Direct mode

{{ connector_result }} is the parsed tool payload. For HTTP-style tools that’s { data, status, headers, statusText } — drill into the response body with {{ connector_result.data }} and the status code with {{ connector_result.status }}. For other tools the shape is whatever the tool returned — check the connector’s documentation.

Knowledge — Query mode (RAG)

Same rule as AI Agent: without a Response Schema, {{ query_result }} is the synthesised answer string; with a schema it’s the structured object.

Knowledge — Embed mode

{{ embed_result }} is { chunkCount, collectionName, documentType }.

Transform, Condition, Loop, Human Approval, Send Email, etc.

Each node type produces data in the shape documented on its node page. Open the specific node page under Node Types for details.
When you need to reshape data between two steps without an LLM, the Transform node lets you author the output shape using these same {{ … }} templates — including {{ item }} / {{ index }} for per-element mapping over an array.

Type preservation

Templates come in two flavors:

Standalone expression — type preserved

When the entire value of a field is a single {{ ... }}, the resolver returns the original type without string conversion:
{
  "total": "{{ input.order.total }}",
  "items": "{{ input.order.items }}"
}
Here total resolves to a number (99.99) and items to an array — not to strings. This is critical when downstream systems expect typed JSON.

Mixed with text — coerced to string

When templates are mixed with literal text, everything becomes a string:
Hi {{ input.customer.name }}, your order total is {{ input.order.total }}.
Resolves to "Hi Alice, your order total is 99.99." — numbers and objects get serialized to JSON inline.

Example — chaining nodes

A workflow that receives a webhook, asks an AI agent to process the payload, then returns an HTTP response:
Webhook  →  AI Agent (outputVariable: joke)  →  Response
Webhook payload:
{ "topic": "programming" }
AI Agent node — Prompt:
Write a short joke about {{ input.topic }}.
AI Agent node — Output Variable: joke Response node — Body:
{
  "status": "ok",
  "topic": "{{ input.topic }}",
  "joke_text": "{{ joke }}"
}
When the webhook fires, the response returns the AI-generated joke with the trigger topic preserved.

Common pitfalls

Referencing a step before setting its output variable

{{ joke }} returns null (and renders as the literal string "null" in mixed contexts) if no upstream node has output variable joke. Check the output variable is set on the correct node.

Forgetting to save and re-compile

Edits to node configuration are saved to the canvas; the compiled version of the workflow graph — what webhooks actually run — is regenerated when the workflow compiles. This happens automatically on Save and when you click Run. If you edit directly via API and skip compile, webhooks will keep running the old compiled version.

Using {{ result }} without specifying which step

result is not a reserved name. If no node has outputVariable: result, this resolves to null. Always name your variables per-step ({{ agent_result }}, {{ user_lookup }}, etc.).

Nested template expressions

{{ {{ foo }}.bar }} doesn’t work — templates don’t compose. If you need dynamic path access, compute the full path in an upstream Transform node and store it as a single string variable.

JSON syntax with templates

In a Response node’s body or any other JSON field:
  • "value": "{{ someStep }}" — works; quotes mark this as a string-or-object slot, the resolver preserves type if the whole value is one template
  • "value": {{ someStep }} — breaks the JSON parser in the editor; wrap templates that fill whole values in quotes

Path syntax cheat sheet

ExpressionWhat it resolves to
{{ input }}the whole trigger payload
{{ input.user.name }}nested object access
{{ input.items[0] }}array index
{{ input.items[0].price }}nested index + field
{{ step_name }}whole output of a step with outputVariable: step_name
{{ step_name.field }}field inside that step’s output
Identifiers may contain letters, digits, underscores, hyphens, and dots. Array brackets use numeric indices.