Human-in-the-loop
Pause a workflow for human approval or input, then resume it.
Some steps shouldn't be fully automated — an approval, a document a person must supply, a review of a high-stakes decision. TurfAI workflows support human-in-the-loop (HITL): a run pauses, surfaces what's pending, and resumes once a human acts. Read the HITL pattern for the rationale.
What to put behind a human
A useful rule of thumb from agent-design guidance: gate an action by its reversibility and blast radius. Let automation run freely for local, reversible steps; require a human for anything destructive, hard to undo, or visible to others.
| Risk | Examples | Default |
|---|---|---|
| Low — local, reversible | enrich a record, draft text, classify a document | Run automatically |
| Medium — externally visible | send an email, post to a channel, write to a shared system | Gate for high-stakes cases |
| High — destructive / hard to reverse | delete data, issue a payment, sign off a decision | Always require approval |
Reversibility/blast-radius framing adapted from Anthropic's Claude prompting guidance. In
TurfAI you implement the gate with a HITL node followed by a decision (see
Approval pattern below).
The lifecycle
1. Detect the pause
Poll execution status as usual. When the run reaches a HITL node, status becomes
awaiting_user_input and the response tells you what's needed:
curl https://apisandbox.turfai.in/api/workflow-executions/456/status \
-H "Authorization: Bearer $TURFAI_JWT"{
"data": {
"id": 456,
"status": "awaiting_user_input",
"awaiting_node": "document-input-1",
"correlation_token": "abc123",
"awaiting_input_schema": {
"type": "object",
"properties": {
"file_url": { "type": "string" },
"document_name": { "type": "string" }
}
}
}
}Use awaiting_input_schema to render a form (or validate programmatically), and keep the
correlation_token — it ties your resume call to this exact pause.
2. Resume with the human's input
curl -X POST https://apisandbox.turfai.in/api/workflow-executions/456/resume \
-H "Authorization: Bearer $TURFAI_JWT" \
-H "Content-Type: application/json" \
-d '{
"correlation_token": "abc123",
"payload": {
"file_url": "gs://bucket/user-uploaded.pdf",
"document_name": "uploaded.pdf"
}
}'{ "data": { "id": 456, "status": "running" } }The workflow continues from where it paused, with the supplied payload merged into its
inputs. Keep polling until completed or failed.
Approval pattern
For an approve/reject gate, follow the HITL node with a decision
task on the supplied input — e.g. resume with { "approved": true }, then branch:
{
"task_type": "decision",
"config": { "operator": "==", "left_operand": "$.approval.approved", "right_operand": "true" }
}The true edge proceeds to the action; the false edge routes to a rejection path.
Tips
- Set a deadline. Track how long a run has been
awaiting_user_inputand escalate or cancel if it stalls. - Persist the token. Store
execution_id+correlation_tokenso any authorized user can complete the step later. - Poll politely. Every 2–5 seconds; don't poll faster than once per second.
Reference
POST /workflow-executions/:id/resume and the awaiting_user_input status in the
Workflow integration guide.