Skip to main content
Building a workflow that’s easy to maintain starts before you touch the canvas. The most reliable workflows are designed with a clear objective, a defined input schema, and an explicit output shape — then assembled using a consistent build pattern that keeps side effects isolated and failures predictable.

Before You Build

Define three things before opening Studio:
1

Objective

Write one sentence describing the outcome this workflow should produce. If you can’t describe it in one sentence, consider splitting it into two workflows.
2

Input

List every field the workflow needs to run. Note the type (string, number, object) and whether each field is required or optional.
3

Output

Describe what should be saved, sent, or returned when the workflow succeeds. Prefer structured keys over free-form text.
Skipping this planning step makes workflows hard to debug and hard to maintain. A five-minute design session saves hours of troubleshooting later.

Build Flow in Studio

1

Open Workflows

Navigate to Studio → Workflows and click New Workflow.
2

Add an Input block

Define the fields your workflow expects — text strings, numbers, or nested objects. This becomes the contract between your workflow and its callers.
3

Add processing blocks

Add Condition blocks to branch logic, Transform blocks to reshape data, and Agent blocks to generate or classify content. See Blocks for the full reference.
4

Wire outputs to inputs

Click a block’s output handle and drag to the next block’s input handle. Reference the connected value in your block config using {{ block_id.output }}.
5

Run in Console

Click the play icon to open the Console. Paste a real input payload and run the workflow. Inspect each block’s output before moving on.
6

Activate

Once tests pass, activate the workflow. It will begin running automatically when its trigger fires.

The Practical Build Pattern

Use this five-step order for every production workflow. Keeping these phases separate makes each one easier to test, debug, and modify independently.

1 — Validate Input

Check that required fields exist and have the correct type before doing anything else. A Condition block or a lightweight Transform block works well here.
block: condition
id: validate_input
condition: "{{ inputs.ticket_id }} != null and {{ inputs.body }} != null"
on_false: stop  # end the run immediately — nothing to process

2 — Fetch Context

Pull any data the workflow needs from Databases, external APIs, or integrations. Keep fetches separate from decisions so failures are easy to isolate.
block: http
id: fetch_customer
url: "https://api.yourcrm.com/customers/{{ inputs.customer_email }}"
method: GET
headers:
  Authorization: "Bearer {{ env.CRM_API_KEY }}"

3 — Transform and Decide

Shape the data and branch as needed. This is where Condition blocks route execution and Agent blocks make judgment calls.
block: agent
id: classify_urgency
prompt: |
  You are a support triage assistant.
  Ticket subject: {{ inputs.subject }}
  Ticket body: {{ inputs.body }}
  Customer tier: {{ fetch_customer.output.tier }}

  Classify the urgency of this ticket.
  Respond with exactly one of: low, medium, high
output_key: urgency

4 — Take Action

Write data, send messages, and call external systems — but only after validation has passed. Moving writes to this phase ensures a bad input never creates a partial record in your external tools.
block: http
id: update_ticket
url: "https://api.yourcrm.com/tickets/{{ inputs.ticket_id }}"
method: PATCH
body:
  urgency: "{{ classify_urgency.output }}"
  status: "triaged"

5 — Return Structured Output

Return a clean set of keys and values. Agents and downstream systems cannot reliably parse free-form text.
block: output
id: workflow_output
fields:
  ticket_id: "{{ inputs.ticket_id }}"
  urgency: "{{ classify_urgency.output }}"
  routed_to: "{{ route_ticket.output.queue }}"
  status: "processed"

Example: Processing a Support Ticket

Here is how the full pattern comes together for a workflow that receives a support ticket, classifies it, and routes it to the right team.
Input: { ticket_id, subject, body, customer_email }

1. Validate   → confirm ticket_id and body are present; stop immediately if not
2. Fetch      → look up customer record and tier from your CRM Database
3. Decide     → run an Agent Block to classify urgency (low / medium / high)
4. Act        → write urgency back to the ticket; post to the matching Slack channel
5. Output     → { ticket_id, urgency, routed_to, status: "processed" }
Each step is a separate block. If step 2 fails, steps 3 through 5 never run — so your external systems stay consistent and you always know which block caused the failure.

Using Workflows as Agent Tools

When you expose a workflow as a tool for an AI agent, the input and output contract becomes even more important. Agents call tools programmatically — they cannot interpret ambiguous schemas or unstructured responses. Follow these rules for agent-facing workflows:
  • Keep the input schema small and explicit. Accept only the fields the workflow actually needs.
  • Return predictable output keys. The agent reads specific keys — don’t change them between revisions without updating the agent’s instructions.
  • Include clear failure messages in output. Return { status: "failed", reason: "ticket_id missing" } rather than throwing an unhandled error.
  • Avoid side effects before validation. The agent may call the workflow with incomplete data during exploration — validate first so nothing is written prematurely.
Add an instruction snippet to your agent telling it how to call this workflow:
When calling the triage_ticket workflow tool:
1. Confirm ticket_id, subject, body, and customer_email are available before calling.
2. Pass the smallest valid payload — omit optional fields if unknown.
3. On failure, read the "reason" key from the response and surface it to the user.
4. On success, report the ticket_id, urgency, and routed_to values.

Common Mistakes to Avoid

Overloading one workflow with too many jobs. If a workflow handles unrelated processes, split it. Each workflow should do one thing well — it will be easier to test, maintain, and debug independently.
Writing to external systems before validation. Always move writes to phase 4. A bad input should never create a partial record in your CRM, database, or messaging tool.
Returning free-form text instead of structured output. Return { status, result_id, message } rather than a paragraph. Agents and downstream integrations cannot parse prose reliably.
Skipping test runs with realistic payloads. Use the Console with actual data — not placeholder strings like "test". Edge cases appear quickly with real values and save you from production surprises.

Next Steps

Blocks

Choose the right block type for each step in your workflow.

Running Workflows

Execute your workflow from the Console, API, or SDK.

Environments

Promote your workflow from development to production safely.

Logs

Debug run failures and trace data flow between blocks.