惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AWS News Blog
AWS News Blog
T
Tenable Blog
Project Zero
Project Zero
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
T
Threatpost
Security Latest
Security Latest
C
Cisco Blogs
L
Lohrmann on Cybersecurity
S
Security @ Cisco Blogs
Google Online Security Blog
Google Online Security Blog
NISL@THU
NISL@THU
AI
AI
V
Vulnerabilities – Threatpost
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Last Watchdog
The Last Watchdog
G
GRAHAM CLULEY
Cloudbric
Cloudbric
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Hacker News: Front Page
U
Unit 42
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MyScale Blog
MyScale Blog
O
OpenAI News
Scott Helme
Scott Helme
V2EX - 技术
V2EX - 技术
P
Proofpoint News Feed
博客园 - 叶小钗
Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cyberwarzone
Cyberwarzone
博客园 - 【当耐特】
H
Heimdal Security Blog
S
Schneier on Security
阮一峰的网络日志
阮一峰的网络日志
Help Net Security
Help Net Security
D
DataBreaches.Net
Y
Y Combinator Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
N
News and Events Feed by Topic
WordPress大学
WordPress大学
P
Palo Alto Networks Blog

Workflow SDK Documentation

Patterns for Defining Tools Human-in-the-Loop Building Durable AI Agents Queueing User Messages Resumable Streams Sleep, Suspense, and Scheduling Streaming Updates from Tools API Reference Workflow Globals Changelog Resilient run start Cookbook Building a World Deploying Astro Express Fastify Hono Getting Started NestJS Next.js Nitro Nuxt Python SvelteKit Vite corrupted-event-log fetch-in-workflow hook-conflict Errors node-js-module-in-workflow serialization-failed start-invalid-workflow-function step-not-registered timeout-in-workflow webhook-invalid-respond-with-value webhook-response-not-sent workflow-not-registered Errors & Retrying Hooks & Webhooks Idempotency Foundations Serialization Starting Workflows Streaming Versioning Workflows and Steps How the Directives Work Encryption Event Sourcing Framework Integrations Understanding Directives Migration Guides Migrating from AWS Step Functions Migrating from Inngest Migrating from Temporal Observability Testing Server-Based Testing createHook defineHook FatalError fetch getStepMetadata getWorkflowMetadata getWritable workflow RetryableError sleep @workflow/vitest DurableAgent @workflow/ai WorkflowChatTransport getHookByToken getRun getWorld workflow/api resumeHook resumeWebhook Chat Session Modeling runtime-decryption-failed Upgrading Workflows abort-signal-timeout-in-workflow Cancellation How Cancellation Works Internal Serializable AbortController and AbortSignal Eager Processing of Steps & Incremental Event Replay TanStack Start Agent Cancellation Sequential & Parallel Execution Workflow Composition Local World | Workflow SDK Postgres World | Workflow SDK Vercel World | Workflow SDK Migrating from trigger.dev Secure Credential Handling Local World | Workflow SDK Postgres World | Workflow SDK Vercel World | Workflow SDK
createWebhook
2026-05-31 · via Workflow SDK Documentation

Create webhooks to suspend and resume workflows via HTTP requests.

Creates a webhook that can be used to suspend and resume a workflow run upon receiving an HTTP request.

Webhooks provide a way for external systems to send HTTP requests directly to your workflow. Unlike hooks which accept arbitrary payloads, webhooks work with standard HTTP Request objects and can return HTTP Response objects.

createWebhook() creates a public endpoint at /.well-known/workflow/v1/webhook/:token, and the token in that URL is the only authorization performed for incoming requests resuming that webhook. This is convenient for prototypes and simple resume links because it avoids creating another route, but if you need stronger security, prefer createHook() behind your own route and authorize the request before calling resumeHook() to avoid unauthenticated workflow resumptions.

import { createWebhook } from "workflow"

export async function webhookWorkflow() {
  "use workflow";
  // `using` automatically disposes the webhook when it goes out of scope
  using webhook = createWebhook();  
  console.log("Webhook URL:", webhook.url);

  const request = await webhook; // Suspends until HTTP request received
  console.log("Received request:", request.method, request.url);
}

Parameters

This function has multiple signatures.

Signature 1

NameTypeDescription
optionsWebhookOptions & { respondWith: "manual"; }

Signature 2

NameTypeDescription
optionsWebhookOptions

Returns

This function has multiple signatures.

Signature 1

Webhook<RequestWithResponse>

Signature 2

The returned Webhook object has:

  • url: The HTTP endpoint URL that external systems can call
  • token: The unique token identifying this webhook
  • getConflict(): A promise that resolves with { runId } identifying the conflicting run if another active hook already owns this token, or null once the webhook endpoint has been registered
  • Implements AsyncIterable<T> for handling multiple requests, where T is Request (default) or RequestWithResponse (manual mode)

When using createWebhook({ respondWith: 'manual' }), the resolved request type is RequestWithResponse, which extends the standard Request interface with a respondWith(response: Response): Promise<void> method for sending custom responses back to the caller.

Use the simplest option that satisfies the prompt:

  • createWebhook() — generated callback URL, and the default 202 Accepted response is fine
  • createWebhook({ respondWith: 'manual' }) — generated callback URL, but you must send a custom body, status, or headers
  • createHook() + resumeHook() — the app resumes from server-side code with a deterministic business token instead of a generated callback URL
Common wrong turns
  • Do not use respondWith: 'manual' just because the flow has a callback URL.
  • Do not use RequestWithResponse unless you chose manual mode.
  • Do not invent a custom callback route when webhook.url is the intended callback surface.

Basic Usage

Create a webhook that receives HTTP requests and logs the request details:

import { createWebhook } from "workflow"

export async function basicWebhookWorkflow() {
  "use workflow";

  using webhook = createWebhook(); 
  console.log("Send requests to:", webhook.url);

  const request = await webhook;

  console.log("Method:", request.method);
  console.log("Headers:", Object.fromEntries(request.headers));

  const body = await request.text();
  console.log("Body:", body);
}

Responding to Webhook Requests (Manual Mode)

Use this section only when the caller requires a non-default HTTP response. If 202 Accepted is acceptable, use createWebhook() without respondWith: "manual".

Pass { respondWith: "manual" } to get a RequestWithResponse object with a respondWith() method. Note that respondWith() must be called from within a step function:

import { createWebhook, type RequestWithResponse } from "workflow"

async function sendResponse(request: RequestWithResponse): Promise<void> {
  "use step";
  await request.respondWith(
    new Response(JSON.stringify({ success: true, message: "Received!" }), {
      status: 200,
      headers: { "Content-Type": "application/json" }
    })
  );
}

export async function respondingWebhookWorkflow() {
  "use workflow";

  using webhook = createWebhook({ respondWith: "manual" });
  console.log("Webhook URL:", webhook.url);

  const request = await webhook;

  // Send a custom response back to the caller
  await sendResponse(request);

  // Continue workflow processing
  const data = await request.json();
  await processData(data);
}

async function processData(data: any): Promise<void> {
  "use step";
  // Process the webhook data
  console.log("Processing:", data);
}

Waiting for Multiple Requests

You can also wait for multiple requests by using the for await...of syntax.

import { createWebhook, type RequestWithResponse } from "workflow"

async function sendAck(request: RequestWithResponse, message: string) {
  "use step";
  await request.respondWith(
    Response.json({ received: true, message })
  );
}

async function processEvent(data: any) {
  "use step";
  console.log("Processing event:", data);
}

export async function eventCollectorWorkflow() {
  "use workflow";

  using webhook = createWebhook({ respondWith: "manual" });
  console.log("Send events to:", webhook.url);

  for await (const request of webhook) { 
    const data = await request.json();

    if (data.type === "done") {
      await sendAck(request, "Workflow complete");
      break;
    }

    await sendAck(request, "Event received");
    await processEvent(data);
  }
}
  • createHook() — Use when the app resumes from server-side code with a deterministic business token.
  • resumeHook() — Pairs with createHook() for deterministic server-side resume.
  • defineHook() — Type-safe hook helper.
  • resumeWebhook() — Low-level runtime API. Most integrations should call webhook.url directly instead of adding a custom callback route.