|
| 1 | +--- |
| 2 | +title: New `waitForEvent` API landed in Workflows |
| 3 | +description: Use the new `waitForEvent` API in Workflows to wait for approvals, additional data and/or webhooks from external systems. |
| 4 | +products: |
| 5 | + - workflows |
| 6 | +date: 2025-02-18T14:00:00Z |
| 7 | +--- |
| 8 | + |
| 9 | +import { Render, TypeScriptExample } from "~/components"; |
| 10 | + |
| 11 | +[Workflows](/workflows/) now allows your workflows to wait for events through the [`waitForEvent`](/workflows/build/events-and-parameters/) API, enabling human-in-loop, approval-driven and/or webhook-reactive workflows and AI agents that can act on external events as they execute. |
| 12 | + |
| 13 | +Calling `step.waitForEvent` is similar to calling any other step in your Workflow: give the step a name, set an optional timeout, and return the event as state: |
| 14 | + |
| 15 | +<TypeScriptExample filename="workflow.ts"> |
| 16 | +```ts |
| 17 | +// Within your Workflow definition |
| 18 | +let event = await step.waitForEvent("unique event name", { timeout: "1 day" }) |
| 19 | +``` |
| 20 | +</TypeScriptExample> |
| 21 | + |
| 22 | +You can then pass an event to a specific Workflow instance by calling `sendEvent`: |
| 23 | + |
| 24 | +<TypeScriptExample filename="index.ts"> |
| 25 | +```ts |
| 26 | +// Within a Worker, Queue handler, or Durable Object |
| 27 | +await env.WORKFLOW.get(instanceId).sendEvent("unique event name", eventPayload) |
| 28 | +``` |
| 29 | +</TypeScriptExample> |
| 30 | + |
| 31 | +For example, you can build Workflows that can wait for third party webhooks by using `await step.waitForEvent` inside the Workflow and `sendEvent` from the [Workers API](/workflows/build/workers-api/#workflowinstance): |
| 32 | + |
| 33 | +<TypeScriptExample filename="index.ts"> |
| 34 | +```ts |
| 35 | +type InboundBillingEvent = { |
| 36 | + name: string; |
| 37 | + timestamp: Date; |
| 38 | + invoiceId: string; |
| 39 | + amount: number; |
| 40 | + description: string; |
| 41 | +} |
| 42 | + |
| 43 | +export class MyWorkflow extends WorkflowEntrypoint<Env, Params> { |
| 44 | + async run(event: WorkflowEvent<Params>, step: WorkflowStep) { |
| 45 | + let state = step.do("my first step", async () => { |
| 46 | + // Code here |
| 47 | + }) |
| 48 | + |
| 49 | + // Pass an optional type |
| 50 | + let invoiceEventData = await step.waitForEvent<InboundBillingEvent>("wait for paid invoice", { timeout: "7 days" }) |
| 51 | + |
| 52 | + let res = await step.do("process invoice", await async () => { |
| 53 | + // Process the invoiceEventData |
| 54 | + // If the payload doesn't work, we can trigger another step.waitForEvent from here too! |
| 55 | + } |
| 56 | + |
| 57 | + // Continue on with the workflow |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +export default { |
| 62 | + async fetch(req: Request, env: Env, ctx: ExecutionContext) { |
| 63 | + let path = new URL(req.url).pathname |
| 64 | + switch (path) { |
| 65 | + case "/runInstance": |
| 66 | + if (req.method === "POST") { |
| 67 | + let params = new URL(req.url).searchParams |
| 68 | + let invoiceId = params.get("invoiceId") |
| 69 | + let instance = await env.WORKFLOW.create({ id: invoiceId }) |
| 70 | + |
| 71 | + return Response.json({ instance_id: instance.id }) |
| 72 | + case "/handleWebhook": |
| 73 | + if (req.method === "POST") { |
| 74 | + let instanceId = req.headers.get("x-workflow-invoice-id") |
| 75 | + let jsonPayload = await req.json() |
| 76 | + await env.WORKFLOW.get(instanceId).sendEvent("process invoice", jsonPayload) |
| 77 | + return Response.json({ success: true }) |
| 78 | + default: |
| 79 | + return Response.json({ error: "Not found" }, { status: 404 }) |
| 80 | + } |
| 81 | + } |
| 82 | +} |
| 83 | +``` |
| 84 | +</TypeScriptExample> |
| 85 | +
|
| 86 | +Visit the Workflows [documentation on events and parameters](/workflows/build/events-and-parameters/) to learn more about the new event API. |
0 commit comments