await step.email('stepId', handler, {
    controlSchema: z.object({
        subject: z.string(),
        components: z.array(z.object({
            type: z.enum(['text', 'button']),
            content: z.string(),
        })),
    }),
});
await step.email('stepId', handler, {
    controlSchema: z.object({
        subject: z.string(),
        components: z.array(z.object({
            type: z.enum(['text', 'button']),
            content: z.string(),
        })),
    }),
});

Channel Steps Interface

All channels follow the same shared interface:
stepId
string
required
This is the unique identifier for the step in the workflow context. It is used to reference and display the step in the dashboard interface.
resolver
Promise
required
This is an async function that returns the content of the step which called Outputs. Each channel has its own output schema.
options
StepOptions
Additional step configuration.

Options Object

This is an optional configuration object that defines: Controls Schema, Provider Overrides, skip and other configurations…
skip
(controls: StepControlSchema) => boolean | Promise<boolean>
A function that returns a boolean value to skip the step. This is helpful when you want to use previous step results or other custom logic to skip the step from executing.
controlSchema
JSON Schema | Zod
This defined the UI Controls exposed in the dashboard for the step. They can be nested and of any JSON Schema supported structure.
providers
ProvidersOverride

Providers Overrides Object

This object used to access and override the underlying deliver providers SDKs. This is useful when you want to customize the content of the notification with provider unique properties.
type ProvidersOverride = {
  [key: ProviderEnum]: ProviderCallback;
};

type ProviderCallback = (
  params: ProviderOverridesParams
) => Promise<ProviderOverrideResponse>;

type ProviderOverridesParams = {
  controls: StepControls;
  output: StepOutput;
};