> ## 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.

# Executing a step

> Define the execute handler for a step block

`defineWorkflowBlockExecute` wires an execute handler to a step block. The handler runs each time a workflow run reaches this step.

## Parameters

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

<ParamField path="execute" type="function" required>
  The handler function. Receives a context object with `config` (typed from the block's configSchema) and `metadata`.

  `metadata` provides context about the current run and workflow:

  | 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 current workflow run. |
  | `uniqueExecutionId` | `string` | Unique ID for this specific execution of the block. Use for idempotency. |
  | `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` | URL to POST to when finishing a deferred execution. Only relevant when the handler returns `{type: "defer"}`. See [Finishing a deferred step](./define-workflow-block-resume-callback). |
</ParamField>

## Example

```ts execute.ts theme={"system"}
import {Workflows} from "attio/server"
import block from "./block"

export default Workflows.defineWorkflowBlockExecute(block, async ({config, metadata}) => {
  const response = await fetch("https://api.example.com/jobs", {
    method: "POST",
    body: JSON.stringify({email: config.recipient_email}),
  })

  if (!response.ok) {
    return {
      type: "error",
      errorMessage: `Request failed: ${response.statusText}`,
      retryable: response.status >= 500,
    }
  }

  const {jobId, shouldSkip} = await response.json()

  if (shouldSkip) {
    return {type: "exit"}
  }

  if (jobId) {
    // Pause and wait for a POST to metadata.finishCallbackUrl
    return {type: "defer"}
  }

  return {type: "outcome", id: "success", data: null}
})
```

## See also

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


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.