Skip to main content
A common requirement for production AI agents is the ability to wait for human input or external events before proceeding. Workflow DevKit’s webhook and hook primitives enable “human-in-the-loop” patterns where workflows pause until a human takes action, allowing smooth resumption of workflows even after days of inactivity, with stability across code deployments.

How It Works

1
defineHook() creates a typed hook that can be awaited in a workflow. When the tool is called, it creates a hook instance using the tool call ID as the token.
2
The workflow pauses at await hook - no compute resources are consumed while waiting.
3
The UI displays the pending tool call with its input data and renders approval controls.
4
The user submits their decision through an API endpoint, which resumes the hook with the approval data.
5
The workflow receives the approval data and resumes execution.

Creating an Approval Tool

Add a tool that allows the agent to deliberately pause execution until a human approves or rejects an action:
1

Define the Hook

Create a typed hook with a Zod schema for validation:
workflows/hooks/booking-approval.ts
2

Implement the Tool

Create a tool that creates a hook instance using the tool call ID as the token:
workflows/chat/steps/tools.ts
The defineHook().create() function must be called from within a workflow context, not from within a step. This is why executeBookingApproval does not have "use step" - it runs in the workflow context where hooks are available.
3

Create the API Route

Create an API endpoint that the UI will call to submit the approval decision:
app/api/hooks/approval/route.ts
4

Create the Approval Component

Build a component that reacts to the tool call data:
components/booking-approval.tsx
5

Render in the Chat UI

Use the component to render the tool call and approval controls:
app/page.tsx

Using Webhooks Directly

For simpler cases where you don’t need type-safe validation, use createWebhook() directly:
workflows/chat/steps/tools.ts
The webhook URL can be called directly with a POST request containing the approval data. This is useful for:
  • External systems that need to call back into your workflow
  • Payment provider callbacks
  • Email-based approval links
  • Slack or Teams integrations

Advanced Patterns

Timeout with Default Action

Combine hooks with sleep() to implement timeouts:
lineNumbers

Multi-Step Approval

Implement multi-level approvals:
lineNumbers
Send approval links via email using webhooks:
lineNumbers