---
slug: /references/notification-provider-module
---

import { TypeList } from "docs-ui"

# How to Create a Notification Provider Module

In this document, you’ll learn how to create a notification provider module and the methods you must implement in it.

---

## 1. Create Module Directory

Start by creating a new directory for your module. For example, `src/modules/my-notification`.

---

## 2. Create the Notification Provider Service

Create the file `src/modules/my-notification/service.ts` that holds the implementation of the notification service.

The Notification Provider Module's main service must extend the `AbstractNotificationProviderService` class imported from `@medusajs/framework/utils`:

```ts title="src/modules/my-notification/service.ts"
import { 
  AbstractNotificationProviderService
} from "@medusajs/framework/utils"

class MyNotificationProviderService extends AbstractNotificationProviderService {
  // TODO add methods
}

export default MyNotificationProviderService
```

### constructor

The constructor allows you to access resources from the module's container using the first parameter,
and the module's options using the second parameter.

If you're creating a client or establishing a connection with a third-party service, do it in the constructor.

#### Example

```ts
import { AbstractNotificationProviderService } from "@medusajs/framework/utils"
import { Logger } from "@medusajs/framework/types"

type InjectedDependencies = {
  logger: Logger
}

type Options = {
  apiKey: string
}

class MyNotificationProviderService extends AbstractNotificationProviderService {
  protected logger_: Logger
  protected options_: Options
  // assuming you're initializing a client
  protected client

  constructor (
    { logger }: InjectedDependencies,
    options: Options
  ) {
    super()

    this.logger_ = logger
    this.options_ = options

    // assuming you're initializing a client
    this.client = new Client(options)
  }
}

export default MyNotificationProviderService
```

### validateOptions

This method validates the options of the provider set in `medusa-config.ts`.
Implementing this method is optional. It's useful if your provider requires custom validation.

If the options aren't valid, throw an error.

#### Example

```ts
class MyNotificationProviderService extends AbstractNotificationProviderService {
  static validateOptions(options: Record<any, any>) {
    if (!options.apiKey) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        "API key is required in the provider's options."
      )
    }
  }
}
```

#### Parameters

<TypeList types={[{"name":"options","type":"`Record<any, any>`","description":"The provider's options.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="validateOptions"/>

#### Returns

<TypeList types={[{"name":"void","type":"`void`","optional":false,"defaultValue":"","description":"This method validates the options of the provider set in `medusa-config.ts`.\nImplementing this method is optional. It's useful if your provider requires custom validation.\n\nIf the options aren't valid, throw an error.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="validateOptions"/>

### send

This method is used to send a notification using the third-party provider or your custom logic.

#### Example

```ts
// other imports...
import {
  ProviderSendNotificationDTO,
  ProviderSendNotificationResultsDTO
} from "@medusajs/framework/types"

class MyNotificationProviderService extends AbstractNotificationProviderService {
  // ...
  async send(
    notification: ProviderSendNotificationDTO
  ): Promise<ProviderSendNotificationResultsDTO> {
    // TODO send the notification using a third-party
    // provider or custom logic.
    // for example:
    return this.client.send({
      email: notification.to,
      template: notification.template,
      template_data: notification.data
    })
  }
}
```

#### Parameters

<TypeList types={[{"name":"notification","type":"[ProviderSendNotificationDTO](../../../types/NotificationTypes/interfaces/types.NotificationTypes.ProviderSendNotificationDTO/page.mdx)","description":"The details of the\nnotification to send.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"to","type":"`string`","description":"The recipient of the notification. It can be email, phone number, or username, depending on the channel.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"channel","type":"`string`","description":"The channel through which the notification is sent, such as 'email' or 'sms'","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"template","type":"`string`","description":"The template name in the provider's system.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"from","type":"`null` \\| `string`","description":"The sender of the notification. It can be email, phone number, or username, depending on the channel.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"attachments","type":"`null` \\| [Attachment](../../../types/NotificationTypes/interfaces/types.NotificationTypes.Attachment/page.mdx)[]","description":"Optional attachments for the notification.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"content","type":"`string`","description":"The content of the attachment, encoded as a base64 string.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"filename","type":"`string`","description":"The filename of the attachment.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"content_type","type":"`string`","description":"The MIME type of the attachment.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"disposition","type":"`string`","description":"The disposition of the attachment, For example, \"inline\" or \"attachment\".","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"id","type":"`string`","description":"The ID, if the attachment is meant to be referenced within the body of the message.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"data","type":"`null` \\| `Record<string, unknown>`","description":"The data that gets passed over to the provider for rendering the notification.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"content","type":"`null` \\| [NotificationContent](../../../types/NotificationTypes/interfaces/types.NotificationTypes.NotificationContent/page.mdx)","description":"The content that gets passed to the provider.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"subject","type":"`string`","description":"the subject of the notification","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"text","type":"`string`","description":"the text content of the notification","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"html","type":"`string`","description":"the html content of the notification","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="send"/>

#### Returns

<TypeList types={[{"name":"Promise","type":"Promise&#60;[ProviderSendNotificationResultsDTO](../../../types/NotificationTypes/interfaces/types.NotificationTypes.ProviderSendNotificationResultsDTO/page.mdx)&#62;","optional":false,"defaultValue":"","description":"The result of sending\nthe notification.","expandable":false,"children":[{"name":"ProviderSendNotificationResultsDTO","type":"[ProviderSendNotificationResultsDTO](../../../types/NotificationTypes/interfaces/types.NotificationTypes.ProviderSendNotificationResultsDTO/page.mdx)","optional":false,"defaultValue":"","description":"","expandable":false,"children":[{"name":"id","type":"`string`","description":"The ID of the notification in the external system, if provided in the response","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="send"/>

---

## 3. Create Module Definition File

Create the file `src/modules/my-notification/index.ts` with the following content:

```ts title="src/modules/my-notification/index.ts"
import MyNotificationProviderService from "./service"
import { 
  ModuleProvider, 
  Modules
} from "@medusajs/framework/utils"

export default ModuleProvider(Modules.NOTIFICATION, {
  services: [MyNotificationProviderService],
})
```

This exports the module's definition, indicating that the `MyNotificationProviderService` is the module's service.

---

## 4. Use Module

To use your Notification Module Provider, add it to the `providers` array of the Notification Module in `medusa-config.ts`:

<Note>

The Notification Module accepts one provider per channel.

</Note>

```ts title="medusa-config.ts"
module.exports = defineConfig({
  // ...
  modules: [
    {
      resolve: "@medusajs/medusa/notification",
      options: {
        providers: [
          // default provider
          {
            resolve: "@medusajs/medusa/notification-local",
            id: "local",
            options: {
              name: "Local Notification Provider",
              channels: ["feed"],
            },
          },
          {
            resolve: "./src/modules/my-notification",
            id: "my-notification",
            options: {
              channels: ["email"],
              // provider options...
            },
          },
        ],
      },
    },
  ]
})
```

Make sure to specify the correct channels for your provider in the `channels` option.

---

## 5. Test it Out

### Create Subscriber

To test out the provider, create a subscriber at `src/subscribers/user-created.ts` with the following content:

```ts title="src/subscribers/user-created.ts"
import { Modules } from "@medusajs/framework/utils"
import {
  SubscriberArgs,
  type SubscriberConfig,
} from "@medusajs/medusa"

export default async function userCreatedHandler({
  event: { data },
  container,
}: SubscriberArgs<{ id: string }>) {
  const notificationModuleService = container.resolve(
    Modules.NOTIFICATION
  )
  const userModule = container.resolve(
    Modules.USER
  )

  const user = await userModule.retrieveUser(data.id)

  await notificationModuleService.createNotifications({
    to: user.email,
    channel: "email",
    template: "new-user"
  })
}

export const config: SubscriberConfig = {
  event: "user.created",
}
```

In the subscriber, you resolve the Notification and User modules. Then, you use the User Module's main service to retrieve the user's details.

Finally, you use the Notification Module's main service to send a notification to the user's email through the `email` channel (assuming that's your provider's channel).

Make sure to replace the value of `template` to the ID of the template in your provider.

### Create User

Use the following command to create a user:

```bash
npx medusa user -e admin@test.com -p supersecret
```

After the user is created, the subscriber is executed, sending the notification using your provider.
