resumeHook

Resume a paused workflow by sending a payload to a hook token or hook object.

Resumes a workflow run by sending a payload to a hook identified by its token or an existing hook object.

resumeHook() returns the resumed hook entity, not the workflow's eventual return value. This is useful when you need the associated runId, hookId, or hook metadata immediately after resumption.

It creates a hook_received event and re-queues the workflow so execution can continue. Use resumeHook() for hooks created with createHook(), whether the token was explicitly set or auto-generated. For hooks created with createWebhook(), use resumeWebhook() instead.

resumeHook is a runtime function that must be called from outside a workflow function.

import { resumeHook } from "workflow/api";

export async function POST(request: Request) {
  const { token, data } = await request.json();

  try {
    const hook = await resumeHook(token, data); 

    console.info(JSON.stringify({
      event: "workflow.hook.resumed",
      token: hook.token,
      hookId: hook.hookId,
      runId: hook.runId,
    }));

    return Response.json({
      runId: hook.runId,
    });
  } catch (error) {
    if (error instanceof Error && error.name === "HookNotFoundError") {
      console.warn(JSON.stringify({
        event: "workflow.hook.not_found",
        token,
      }));

      return Response.json(
        { error: "Hook not found", token },
        { status: 404 }
      );
    }

    console.error(JSON.stringify({
      event: "workflow.hook.resume_failed",
      token,
      error: error instanceof Error ? error.message : String(error),
    }));

    return Response.json(
      { error: "Failed to resume hook" },
      { status: 500 }
    );
  }
}

API Signature

Parameters

NameTypeDescription
tokenOrHookstring | HookThe unique token identifying the hook, or the hook object itself
payloadNonNullable<T>The data payload to send to the hook
encryptionKeyOverrideCryptoKey

Returns

Returns a Promise<Hook> that resolves to:

NameTypeDescription
runIdstringThe unique identifier of the workflow run this hook belongs to.
hookIdstringThe unique identifier of this hook within the workflow run.
tokenstringThe secret token used to reference this hook.
ownerIdstringThe owner ID (team or user) that owns this hook.
projectIdstringThe project ID this hook belongs to.
environmentstringThe environment (e.g., "production", "preview", "development") where this hook was created.
createdAtDateThe timestamp when this hook was created.
metadataunknownOptional metadata associated with the hook, set when the hook was created.
specVersionnumberThe spec version when this hook was created.
isWebhookbooleanWhether this hook is resumable via the public webhook endpoint. undefined = legacy (treated as true for backwards compat).

Error Behavior

A missing hook token is only one failure mode. resumeHook() can also fail while dehydrating the payload, creating the hook_received event, or re-queueing the workflow. In HTTP handlers, map missing hooks to 404 and unexpected failures to 500 so operational failures stay visible.

resumeHook() resolves to the hook record that was resumed. Use hook.runId with getRun() if you want to inspect the workflow after resumption; it does not wait for the workflow to finish.

Examples

Basic API Route

Using resumeHook in a basic API route to resume a hook:

import { resumeHook } from "workflow/api";

export async function POST(request: Request) {
  const { token, data } = await request.json();

  try {
    const hook = await resumeHook(token, data); 

    return Response.json({
      success: true,
      runId: hook.runId
    });
  } catch (error) {
    if (error instanceof Error && error.name === "HookNotFoundError") {
      return Response.json({ error: "Hook not found" }, { status: 404 });
    }
    return Response.json({ error: "Failed to resume hook" }, { status: 500 });
  }
}

With Type Safety

Defining a payload type and using resumeHook to resume a hook with type safety:

import { resumeHook } from "workflow/api";

type ApprovalPayload = {
  approved: boolean;
  comment: string;
};

export async function POST(request: Request) {
  const { token, approved, comment } = await request.json();

  try {
    const hook = await resumeHook<ApprovalPayload>(token, { 
      approved, 
      comment, 
    }); 

    return Response.json({ runId: hook.runId });
  } catch (error) {
    if (error instanceof Error && error.name === "HookNotFoundError") {
      return Response.json({ error: "Hook not found" }, { status: 404 });
    }
    return Response.json({ error: "Failed to resume hook" }, { status: 500 });
  }
}

Server Action (Next.js)

Using resumeHook in Next.js server actions to resume a hook:

"use server";

import { resumeHook } from "workflow/api";

export async function approveRequest(token: string, approved: boolean) {
  try {
    const hook = await resumeHook(token, { approved });
    return hook.runId;
  } catch (error) {
    throw new Error("Failed to resume hook");
  }
}

Passing a Hook Object

Instead of a token string, you can pass a Hook object directly (e.g. one returned by getHookByToken()):

import { getHookByToken, resumeHook } from "workflow/api";

export async function POST(request: Request) {
  const { token, data } = await request.json();

  try {
    const hook = await getHookByToken(token);

    // Validate metadata before resuming
    console.log("Hook metadata:", hook.metadata);

    const resumedHook = await resumeHook(hook, data); 
    return Response.json({ success: true, runId: resumedHook.runId });
  } catch (error) {
    if (error instanceof Error && error.name === "HookNotFoundError") {
      return Response.json({ error: "Hook not found" }, { status: 404 });
    }
    return Response.json({ error: "Failed to resume hook" }, { status: 500 });
  }
}