---
title: Human in the Loop
---

import { Callout } from 'fumadocs-ui/components/callout'
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
import { Image } from '@/components/ui/image'
import { Video } from '@/components/ui/video'
import { FAQ } from '@/components/ui/faq'

The Human in the Loop block pauses workflow execution and waits for human intervention before continuing. Use it to add approval gates, collect feedback, or gather additional input at critical decision points.

<div className="flex justify-center">
  <Image
    src="/static/blocks/hitl-1.png"
    alt="Human in the Loop Block Configuration"
    width={500}
    height={400}
    className="my-6"
  />
</div>

When execution reaches this block, the workflow pauses indefinitely until a human provides input through the approval portal, API, or webhook.

<div className="flex justify-center">
  <Image
    src="/static/blocks/hitl-2.png"
    alt="Human in the Loop Approval Portal"
    width={700}
    height={500}
    className="my-6"
  />
</div>

## Configuration Options

### Display Data

Defines what data is displayed to the approver. This is the context shown in the approval portal to help them make an informed decision.

Use the visual builder or JSON editor to structure the data. Reference workflow variables using `<blockName.output>` syntax.

```json
{
  "customerName": "<agent1.content.name>",
  "proposedAction": "<router1.selectedPath>",
  "confidenceScore": "<evaluator1.score>",
  "generatedEmail": "<agent2.content>"
}
```

### Notification

Configures how approvers are alerted when approval is needed. Supported channels include:

- **Slack** - Messages to channels or DMs
- **Gmail** - Email with approval link
- **Microsoft Teams** - Team channel notifications
- **SMS** - Text alerts via Twilio
- **Webhooks** - Custom notification systems

Include the approval URL (`<blockId.url>`) in your notification messages so approvers can access the portal.

### Resume Form

Defines the fields approvers fill in when responding. This data becomes available to downstream blocks after the workflow resumes.

```json
{
  "approved": {
    "type": "boolean",
    "description": "Approve or reject this request"
  },
  "comments": {
    "type": "string",
    "description": "Optional feedback or explanation"
  }
}
```

Access resume data in downstream blocks using `<blockId.resumeInput.fieldName>`. 

## Approval Methods

<Tabs items={['Approval Portal', 'API', 'Webhook']}>
  <Tab>
    ### Approval Portal
    
    Every block generates a unique portal URL (`<blockId.url>`) with a visual interface showing all paused output data and form fields for resume input. Mobile-responsive and secure.
    
    Share this URL in notifications for approvers to review and respond.
  </Tab>
  <Tab>
    ### REST API
    
    Programmatically resume workflows:
    
    ```bash
    POST /api/workflows/{workflowId}/executions/{executionId}/resume/{blockId}
    
    {
      "approved": true,
      "comments": "Looks good to proceed"
    }
    ```
    
    Build custom approval UIs or integrate with existing systems.
  </Tab>
  <Tab>
    ### Webhook
    
    Add a webhook tool to the Notification section to send approval requests to external systems. Integrate with ticketing systems like Jira or ServiceNow.
  </Tab>
</Tabs>

## Common Use Cases

**Content Approval** - Review AI-generated content before publishing
```
Agent → Human in the Loop → API (Publish)
```

**Multi-Stage Approvals** - Chain multiple approval steps for high-stakes decisions
```
Agent → Human in the Loop (Manager) → Human in the Loop (Director) → Execute
```

**Data Validation** - Verify extracted data before processing
```
Agent (Extract) → Human in the Loop (Validate) → Function (Process)
```

**Quality Control** - Review AI outputs before sending to customers
```
Agent (Generate) → Human in the Loop (QA) → Gmail (Send)
```

## Block Outputs

**`url`** - Unique URL for the approval portal
**`resumeEndpoint`** - Resume API endpoint URL
**`response`** - Display data shown to the approver (json)
**`submission`** - Form submission data from the approver (json)
**`submittedAt`** - ISO timestamp when the workflow was resumed
**`resumeInput.*`** - All fields defined in Resume Form become available after the workflow resumes

Access using `<blockId.resumeInput.fieldName>`.

## Example

**Paused Output:**
```json
{
  "title": "<agent1.content.title>",
  "body": "<agent1.content.body>",
  "qualityScore": "<evaluator1.score>"
}
```

**Resume Input:**
```json
{
  "approved": { "type": "boolean" },
  "feedback": { "type": "string" }
}
```

**Downstream Usage:**
```javascript
// Condition block
<approval1.resumeInput.approved> === true
```
The example below shows an approval portal as seen by an approver after the workflow is paused. Approvers can review the data and provide inputs as a part of the workflow resumption. The approval portal can be accessed directly via the unique URL, `<blockId.url>`.

<div className="mx-auto w-full overflow-hidden rounded-lg my-6">
  <Video src="hitl-resume.mp4" width={700} height={450} />
</div>

## Related Blocks

- **[Condition](/blocks/condition)** - Branch based on approval decisions
- **[Variables](/blocks/variables)** - Store approval history and metadata
- **[Response](/blocks/response)** - Return workflow results to API callers

<FAQ items={[
  { question: "How long does the workflow stay paused?", answer: "The workflow pauses indefinitely until a human provides input through the approval portal, the REST API, or a webhook. There is no automatic timeout — it will wait until someone responds." },
  { question: "What notification channels can I use to alert approvers?", answer: "You can configure notifications through Slack, Gmail, Microsoft Teams, SMS (via Twilio), or custom webhooks. Include the approval URL in your notification message so approvers can access the portal directly." },
  { question: "How do I access the approver's input in downstream blocks?", answer: "Use the syntax <blockId.resumeInput.fieldName> to reference specific fields from the resume form. For example, if your block ID is 'approval1' and the form has an 'approved' field, use <approval1.resumeInput.approved>." },
  { question: "Can I chain multiple Human in the Loop blocks for multi-stage approvals?", answer: "Yes. You can place multiple Human in the Loop blocks in sequence to create multi-stage approval workflows. Each block pauses independently and can have its own notification configuration and resume form fields." },
  { question: "Can I resume the workflow programmatically without the portal?", answer: "Yes. Each block exposes a resume API endpoint that you can call with a POST request containing the form data as JSON. This lets you build custom approval UIs or integrate with existing systems like Jira or ServiceNow." },
  { question: "What outputs are available after the workflow resumes?", answer: "The block outputs include the approval portal URL, the resume API endpoint URL, the display data shown to the approver, the form submission data, the raw resume input, and an ISO timestamp of when the workflow was resumed." },
]} />
