> ## Documentation Index
> Fetch the complete documentation index at: https://docs.attio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Finishing a deferred step

> Define the finish handler for a deferred step block

`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

<ParamField path="block" type="WorkflowBlock" required>
  The block returned by `defineWorkflowBlock` in `block.ts`.
</ParamField>

<ParamField path="finish" type="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:

  | Field               | Type     | Description                                                                                                                  |
  | ------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
  | `workflowId`        | `string` | ID of the workflow this block belongs to.                                                                                    |
  | `workflowVersionId` | `string` | ID of the active workflow version.                                                                                           |
  | `workflowBlockId`   | `string` | ID of this block instance within the workflow.                                                                               |
  | `workflowRunId`     | `string` | ID of the workflow run being finished.                                                                                       |
  | `uniqueExecutionId` | `string` | The same ID that was present in `execute`'s metadata. Use it to correlate the deferred execution with the incoming callback. |
  | `workflowTitle`     | `string` | Human-readable title of the workflow.                                                                                        |
  | `workflowUrl`       | `string` | Link to the workflow in the Attio UI.                                                                                        |
  | `runUrl`            | `string` | Link to the current run in the Attio UI.                                                                                     |
  | `finishCallbackUrl` | `string` | The URL that was posted to. Included for reference; you do not normally need to use it here.                                 |
</ParamField>

## Example

```ts finish.ts theme={"system"}
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

* [Executing a step](./define-workflow-block-execute): step execute handler
* [Outcome schema](./outcome-schema): typing the data field in return values
* [File structure](./file-structure): complete folder layout for trigger and step blocks
