# Workflow Hooks

In this chapter, you'll learn what workflow hooks are and how to use them.

## What is a Workflow Hook?

A workflow hook is a specific point in a workflow where you can inject custom functionality. This custom functionality is called a hook handler.

Medusa exposes hooks in many of its workflows that are used in its API routes. You can consume those hooks to add your custom logic.

Refer to the [Workflows Reference](https://docs.medusajs.com/resources/medusa-workflows-reference) to view all workflows and their hooks.

You want to perform a custom action during a workflow's execution, such as when a product is created.

***

## How to Consume a Hook?

A workflow has a special `hooks` property. This property is an object that contains all available hooks.

So, in a TypeScript or JavaScript file created under the `src/workflows/hooks` directory:

1. Import the workflow.
2. Access the hook using the `hooks` property.
3. Pass a step function as a parameter to the hook.

For example, to consume the `productsCreated` hook of Medusa's `createProductsWorkflow`, create the file `src/workflows/hooks/product-created.ts` with the following content:

```ts title="src/workflows/hooks/product-created.ts" highlights={handlerHighlights}
import { createProductsWorkflow } from "@medusajs/medusa/core-flows"

createProductsWorkflow.hooks.productsCreated(
  async ({ products }, { container }) => {
    // TODO perform an action
  }
)
```

The `productsCreated` hook is available in the workflow's `hooks` property.

You call the hook and pass a step function (the hook handler) as a parameter.

Now, when a product is created using the [Create Product API route](https://docs.medusajs.com/api/admin#products_postproducts), your hook handler runs after the product is created.

A hook can have only one handler. So, you can't consume the same hook multiple times.

Refer to the [createProductsWorkflow reference](https://docs.medusajs.com/resources/references/medusa-workflows/createProductsWorkflow) to see at which point the hook handler is executed.

### Hook Handler Parameter

Since a hook handler is essentially a step function, it receives the hook's input as a first parameter, and an object holding a `container` property as a second parameter.

Each hook has different input. For example, the `productsCreated` hook receives an object with a `products` property that contains the created product.

You can find the input for each workflow's hooks in the [Core Workflows Reference](https://docs.medusajs.com/resources/medusa-workflows-reference).

### Hook Handler Compensation

Since the hook handler is a step function, you can set its compensation function as a second parameter of the hook.

For example:

```ts title="src/workflows/hooks/product-created.ts"
import { createProductsWorkflow } from "@medusajs/medusa/core-flows"

createProductsWorkflow.hooks.productsCreated(
  async ({ products }, { container }) => {
    // TODO perform an action

    return new StepResponse(undefined, { ids })
  },
  async ({ ids }, { container }) => {
    // undo the performed action
  }
)
```

The compensation function runs if an error occurs in the workflow. It undoes the actions performed by the hook handler.

The compensation function receives the second parameter passed to the `StepResponse` returned by the step function as input.

It also accepts an object with a `container` property as a second parameter. This allows you to resolve resources from the Medusa container.

### Additional Data Property

Medusa's workflows include an `additional_data` property in the hook's input:

```ts title="src/workflows/hooks/product-created.ts" highlights={[["4", "additional_data"]]}
import { createProductsWorkflow } from "@medusajs/medusa/core-flows"

createProductsWorkflow.hooks.productsCreated(
  async ({ products, additional_data }, { container }) => {
    // TODO perform an action
  }
)
```

This property is an object that contains additional data passed to the workflow through the request sent to the API route.

Learn how to pass `additional_data` in requests to API routes in the [Additional Data](https://docs.medusajs.com/learn/fundamentals/api-routes/additional-data) chapter.

### Pass Additional Data to Workflow

You can also pass additional data when running the workflow. Pass it as a parameter to the workflow's `.run` method:

```ts title="src/workflows/hooks/product-created.ts" highlights={[["10", "additional_data"]]}
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { createProductsWorkflow } from "@medusajs/medusa/core-flows"

export async function POST(req: MedusaRequest, res: MedusaResponse) {
  await createProductsWorkflow(req.scope).run({
    input: { 
      products: [
        // ...
      ], 
      additional_data: {
        custom_field: "test",
      },
    },
  })
}
```

Your hook handler then receives the passed data in the `additional_data` object.


---

The best way to deploy Medusa is through Medusa Cloud where you get autoscaling production infrastructure fine tuned for Medusa. Create an account by signing up at cloud.medusajs.com/signup.
