Channel Steps Interface

Channel steps are used to send notifications to your Subscribers. Each channel can optionally configure the provider to customise content, enabling you to create enhanced content aligned with the specification of the provider. For example, you might like to use Slack blocks to send your Chat message.

All channels follow the same interface:

await step.email('new-post', async (inputs) => {
    return {
        subject: 'You received a post',
        body: `<html><body>A new post has been created</body></html>`,
    }
}, options);
  • new-post is the unique to the workflow identifier for this step. You cannot have 2 steps using the same identifier
  • resolver function, used to return the content of the channel.
  • options this is an optional configuration object that defines: Input Schema, Provider Overrides, skip and other configurations…

E-mail

E-mail expected to be an object with the following properties:

  • subject - The subject of the email
  • body - The HTML body of the email

Any content generation framework like React Email can be used here to generate the HTML Content.

await step.email('send-email', async (inputs) => {
  return {
    subject: 'You received a post',
    body: `<html><body>A new post has been created</body></html>`,
  };
});

In-App

await step.inApp('send-inapp', async (inputs) => {
  return {
    body: `A new post has been created`,
  };
});

SMS

await step.sms('send-sms', async () => {
  return {
    body: 'A new post has been created',
  };
});

Push

await step.push('send-push', async () => {
  return {
    subject: 'You received a post',
    body: 'A new post has been created',
  };
});

Chat

await step.chat('send-chat', async () => {
  return {
    body: 'A new post has been created',
  };
});

Action Steps Interface

Delay

Use the delay action whenever you need to pause the execution of your workflow for a period of time.

await step.delay('delay-1-week', async () => {
  return {
	  unit: 'weeks', // 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months'
	  amount: 1, // the number of units to delay workflow execution for
	};
});

Digest

Use the digest action whenever you want to aggregate events into an array for a period of time.

await step.digest('digest-3-days', async () => {
  return {
	  unit: 'days', // 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months'
	  amount: 3, // the number of units to digest events for
	};
});

Provider Overrides

Provider overrides are used to customise the content of the notification for a specific provider. For example, you might like to use Slack blocks to send your Chat message.

Those overrides are mapped directly to the provider specific SDKs, so you can use the same properties and methods that you would use in the provider SDK.

await step.chat('send-chat', async () => {
  return {
    body: 'A new post has been created',
  };
}, {
    providers: {
        slack: ({ inputs }) => ({
            text: 'A new post has been created',
            blocks: [
                {
                    type: 'section',
                    text: {
                        type: 'mrkdwn',
                        text: 'A new post has been created',
                    },
                },
            ],
        }),
    }
});

Currently we only support Slack provider overrides. We are working on adding more providers.

When overriding a provider specific behaviour, Novu still requires the default content to be returned from the resolver function. This is because the default content is used for the fallback provider, or when the provider override is not available.

Skip Step

A step can be conditionally skipped by returning true from the resolver function. This is helpful when you want to use your existing user-preference system instead of Novu. Or conditionally skip a step if it’s not relevant any more for delivery.

await step.chat('send-chat', async () => {
  return {
    body: 'A new post has been created',
  };
}, {
    skip: () => true,
});