Skip to main content
defineWorkflowBlockFinish wires a finish handler to a step block. The handler runs when a request arrives at metadata.finishCallbackUrl, for example when a long-running upstream job posts back its result. This handler is only needed when execute returns {type: "defer"}.

Parameters

block
WorkflowBlock
required
The block returned by defineWorkflowBlock in block.ts.
finish
function
required
The handler function. Receives the raw req (a standard Request object) and a context object with config (typed from the block’s configSchema) and metadata.metadata provides run context and the execution ID for correlating the callback with the original deferred execution:
FieldTypeDescription
workflowIdstringID of the workflow this block belongs to.
workflowVersionIdstringID of the active workflow version.
workflowBlockIdstringID of this block instance within the workflow.
workflowRunIdstringID of the workflow run being finished.
uniqueExecutionIdstringThe same ID that was present in execute’s metadata. Use it to correlate the deferred execution with the incoming callback.
workflowTitlestringHuman-readable title of the workflow.
workflowUrlstringLink to the workflow in the Attio UI.
runUrlstringLink to the current run in the Attio UI.
finishCallbackUrlstringThe URL that was posted to. Included for reference; you do not normally need to use it here.

Example

finish.ts
import {Workflows} from "attio/server"
import block from "./block"

export default Workflows.defineWorkflowBlockFinish(block, async (req, {config, metadata}) => {
  const payload = await req.json()

  if (payload.status === "pending") {
    // Job not done yet — stay deferred and wait for the next callback
    return {type: "no-op"}
  }

  if (payload.status === "cancelled") {
    // End the run without raising an error
    return {type: "exit"}
  }

  if (payload.status === "failed") {
    // Surface the error; set retryable: true for transient failures
    return {
      type: "error",
      errorMessage: payload.message,
      retryable: payload.transient, // optional, defaults to false
    }
  }

  // Continue the workflow down the "success" branch
  return {type: "outcome", id: "success", data: null}
})

See also