> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modulex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflows & runs — help

> Answers to common questions about building and running workflows in ModuleX: the nine node types, passing data with node references, pausing for input, cancelling a run, and watching a run live.

export const MediaEmbed = ({id, type = 'screenshot', caption = '', ext, ratio = '16 / 9'}) => {
  const isVideo = type === 'video' || type === 'app_video';
  const resolvedExt = ext || (isVideo ? 'mp4' : type === 'screenshot' ? 'webp' : 'svg');
  const src = 'https://media.modulex.dev/' + id + '.' + resolvedExt;
  const [status, setStatus] = useState('loading');
  const [isDev, setIsDev] = useState(false);
  const [inView, setInView] = useState(false);
  const boxRef = useRef(null);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const h = window.location.hostname;
    setIsDev(h === 'localhost' || h === '127.0.0.1' || h.endsWith('.mintlify.app'));
  }, []);
  useEffect(() => {
    if (inView) return;
    if (typeof IntersectionObserver === 'undefined') {
      setInView(true);
      return;
    }
    const el = boxRef.current;
    if (!el) return;
    const io = new IntersectionObserver(entries => {
      if (entries.some(e => e.isIntersecting)) {
        setInView(true);
        io.disconnect();
      }
    }, {
      rootMargin: '300px'
    });
    io.observe(el);
    return () => io.disconnect();
  }, [inView]);
  if (status === 'missing') {
    if (!isDev) return null;
    return <div style={{
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      gap: '0.4rem',
      padding: '1rem 1.25rem',
      margin: '1.25rem 0',
      width: '100%',
      aspectRatio: ratio,
      boxSizing: 'border-box',
      border: '1px dashed rgba(128,128,128,0.45)',
      borderRadius: '0.75rem',
      background: 'rgba(128,128,128,0.06)',
      color: 'currentColor',
      fontSize: '0.85rem',
      lineHeight: 1.45
    }}>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '0.5rem',
      opacity: 0.75
    }}>
          <span aria-hidden="true">🎬</span>
          <code style={{
      fontSize: '0.75rem'
    }}>{id}</code>
          <span style={{
      fontSize: '0.65rem',
      textTransform: 'uppercase',
      letterSpacing: '0.04em',
      padding: '0.1rem 0.4rem',
      borderRadius: '0.4rem',
      background: 'rgba(128,128,128,0.18)'
    }}>
            {type}
          </span>
        </div>
        <div style={{
      opacity: 0.9
    }}>{caption || 'Media not uploaded yet.'}</div>
        <div style={{
      fontSize: '0.7rem',
      opacity: 0.5
    }}>
          Upload to R2 as <code>{id}.{resolvedExt}</code> — preview only, hidden in production.
        </div>
      </div>;
  }
  const mediaStyle = {
    display: status === 'loaded' ? 'block' : 'none',
    width: '100%',
    height: 'auto',
    borderRadius: '0.75rem'
  };
  const media = isVideo ? <video src={inView ? src : undefined} autoPlay loop muted playsInline preload="metadata" onLoadedData={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} /> : <img src={inView ? src : undefined} alt={caption} onLoad={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} />;
  return <figure style={{
    margin: '1.25rem 0'
  }}>
      <div ref={boxRef} style={status === 'loaded' ? {
    width: '100%'
  } : {
    width: '100%',
    aspectRatio: ratio,
    borderRadius: '0.75rem',
    background: 'rgba(128,128,128,0.06)'
  }}>
        {media}
      </div>
      {status === 'loaded' && caption ? <figcaption style={{
    marginTop: '0.5rem',
    textAlign: 'center',
    fontSize: '0.85rem',
    opacity: 0.7
  }}>
          {caption}
        </figcaption> : null}
    </figure>;
};

A workflow is a graph of steps you connect on a canvas; a run is one execution of that workflow. This page answers the questions people ask most often when building and running workflows.

<MediaEmbed id="MX-MEDIA-4530" type="app_video" caption={"Building and running a workflow end to end in the Workflow Builder."} />

## Quick links

<CardGroup cols={2}>
  <Card title="Workflow builder overview" icon="square-mouse-pointer" href="/workflow-builder/overview">
    Where you build workflows on the visual canvas.
  </Card>

  <Card title="Node types overview" icon="boxes-stacked" href="/workflow-builder/nodes/overview">
    The nine node types and what each one does.
  </Card>
</CardGroup>

## Common questions

<AccordionGroup>
  <Accordion title="How do I build and run a workflow?">
    Open the [Workflow Builder](/workflow-builder/overview), add nodes to the canvas, connect them in the order you want them to run, then save and deploy. Click Run to execute it in the app, or trigger it from the API. See [running workflows](/workflow-builder/execution/running) for the in-app run view and [run via API](/workflow-builder/execution/api-endpoint) to trigger one from code.
  </Accordion>

  <Accordion title="What node types are there?">
    There are nine node types: LLM, Tool, Function, Agent, Conditional, Interrupt, Transformer, Guardrails, and Knowledge. Each one does a different kind of work in a run. The [node types overview](/workflow-builder/nodes/overview) explains what each does and when to use it.
  </Accordion>

  <Accordion title="How do I pass data between nodes?">
    Reference an earlier node's output with the `{{node_id.field}}` syntax — for example, `{{search.results}}` pulls the `results` value from the node with the id `search`. Every node writes its result into the run under its own id, so any later node can read it. See [variables & references](/workflow-builder/variables-and-references).
  </Accordion>

  <Accordion title="Can I pause a workflow to ask the user something?">
    Yes. Add an Interrupt node where you want the run to wait. When the run reaches it, the run pauses, asks your question, and waits for an answer before continuing. See the [Interrupt node](/workflow-builder/nodes/interrupt).
  </Accordion>

  <Accordion title="How do I stop a running workflow?">
    Cancel it from the run view in the app, or call the cancel endpoint from code. Cancellation is graceful: the run stops after the current node finishes, not mid-step. Only runs that are still running or paused can be cancelled. See [running workflows](/workflow-builder/execution/running).
  </Accordion>

  <Accordion title="How do I watch a run live?">
    Stream it. In the app, the run view shows each step as it happens. From code, open the run's event stream — in the SDKs this is the `listen()` method, which yields events as they occur until the run finishes. See [running workflows](/workflow-builder/execution/running).
  </Accordion>
</AccordionGroup>

## Run a workflow from code

When you trigger a run, ModuleX returns immediately with the run details, then you open a separate stream to watch progress. Authenticate every request with `Authorization: Bearer mx_live_…` and the `X-Organization-ID` header. In the SDKs, pass your API key and organization id when you create the client.

<CodeGroup>
  ```bash cURL theme={null}
  # 1. Start the run — returns immediately with a run_id
  curl -X POST https://api.modulex.dev/workflows/run \
    -H "Authorization: Bearer mx_live_your_api_key" \
    -H "X-Organization-ID: org_your_org_id" \
    -H "Content-Type: application/json" \
    -d '{
      "workflow_id": "wf_29ab83c1",
      "input": { "topic": "release notes" }
    }'

  # 2. Watch it live over the event stream
  curl -N https://api.modulex.dev/workflows/listen/run_7k8l9m0n \
    -H "Authorization: Bearer mx_live_your_api_key" \
    -H "X-Organization-ID: org_your_org_id"

  # 3. Cancel it (graceful — stops after the current node)
  curl -X POST https://api.modulex.dev/workflows/cancel/run_7k8l9m0n \
    -H "Authorization: Bearer mx_live_your_api_key" \
    -H "X-Organization-ID: org_your_org_id" \
    -H "Content-Type: application/json" \
    -d '{ "reason": "User requested cancellation" }'
  ```

  ```python Python theme={null}
  from modulex import Modulex

  client = Modulex(
      api_key="mx_live_your_api_key",
      organization_id="org_your_org_id",
  )

  # 1. Start the run
  run = await client.executions.run(
      workflow_id="wf_29ab83c1",
      input={"topic": "release notes"},
  )

  # 2. Watch it live — listen() yields events until the run finishes
  async for event in client.executions.listen(run.run_id):
      print(event["type"])

  # 3. Cancel it (graceful)
  await client.executions.cancel(run.run_id, reason="User requested cancellation")
  ```

  ```javascript JavaScript theme={null}
  import { Modulex } from "modulex-js";

  const client = new Modulex({
    apiKey: "mx_live_your_api_key",
    organizationId: "org_your_org_id",
  });

  // 1. Start the run
  const run = await client.executions.run({
    workflowId: "wf_29ab83c1",
    input: { topic: "release notes" },
  });

  // 2. Watch it live — listen() yields events until the run finishes
  for await (const event of client.executions.listen(run.runId)) {
    console.log(event.type);
  }

  // 3. Cancel it (graceful)
  await client.executions.cancel(run.runId, { reason: "User requested cancellation" });
  ```
</CodeGroup>

<Note>
  Running a workflow on ModuleX-managed models and tools consumes credits, and the run is blocked if your organization is out of credits. See [usage gating & limits](/billing/usage-gating) and [errors & troubleshooting](/help/errors-troubleshooting).
</Note>

## Related help

<CardGroup cols={2}>
  <Card title="AI Composer & Assistant — help" icon="sparkles" href="/help/composer-assistant">
    Generate a workflow from a plain-English prompt, or let the Assistant work step by step.
  </Card>

  <Card title="Errors & troubleshooting — help" icon="circle-alert" href="/help/errors-troubleshooting">
    What common errors mean and how to fix a failed run.
  </Card>
</CardGroup>
