---
title: "Create a workflow"
method: POST
path: "/v2/workflows"
tags: ["Workflows"]
---

# Create a workflow

`POST /v2/workflows`

## Request

- Base URL: `https://api.notifly.io`
- URL: `https://api.notifly.io/v2/workflows`
- Auth: API key in header `Authorization`

Creates a new workflow in the Notifly environment

## Request body

- CreateWorkflowDto
  - `name` string, required: Name of the workflow
  - `description` string: Description of the workflow
  - `tags` string[]: Tags associated with the workflow
  - `active` boolean: Whether the workflow is active
  - `validatePayload` boolean: Enable or disable payload schema validation
  - `payloadSchema` object, nullable: The payload JSON Schema for the workflow
  - `isTranslationEnabled` boolean: Enable or disable translations for this workflow
  - `agent` WorkflowAgentConfigDto
    - `identifier` string, required: Public agent identifier used to route this workflow through an agent's connected channels.
    - `providers` object: Optional per-provider overrides keyed by providerId (e.g. novu-email-agent). Today only Novu Email replyTo is supported.
  - `workflowId` string, required: Unique identifier for the workflow
  - `steps` union[], required: Steps of the workflow
    - union
      - InAppStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the In-App step.
          - InAppControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `body` string: Content/body of the in-app message. Required if subject is empty.
            - `subject` string: Subject/title of the in-app message. Required if body is empty.
            - `avatar` string: URL for an avatar image. Must be a valid URL or start with / or {{ variable }}.
            - `primaryAction` ActionDto
              - …
            - `secondaryAction` ActionDto
              - …
            - `redirect` RedirectDto
              - …
            - `disableOutputSanitization` boolean: Disable sanitization of the output.
            - `data` object: Additional data payload for the step.
          - object
      - EmailStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the Email step.
          - EmailControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `subject` string, required: Subject of the email.
            - `body` string, required: Body content of the email, either a valid Maily JSON object, or html string.
            - `editorType` 'block' | 'html': Type of editor to use for the body.
            - `disableOutputSanitization` boolean: Disable sanitization of the output.
            - `layoutId` string, nullable: Layout ID to use for the email. Null means no layout, undefined means default layout.
            - `from` EmailFromControlDto
              - …
            - `useProviderDefaults` boolean: When true, sender name/email use the primary email integration defaults and skip workflow agent defaults.
            - `replyTo` string: Step-level Reply-To override. When unset, inherits the workflow agent reply-to.
            - `preheader` string: One-line inbox preview text shown next to the subject.
          - object
      - SmsStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the SMS step.
          - SmsControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `body` string: Content of the SMS message.
          - object
      - PushStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the Push step.
          - PushControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `subject` string: Subject/title of the push notification.
            - `body` string: Body content of the push notification.
          - object
      - ChatStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the Chat step.
          - ChatControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `body` string: Content of the chat message.
            - `editorType` 'block' | 'text': Type of editor to use for the body. When omitted, inferred from the body: Maily JSON is "block", otherwise "text".
          - object
        - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`). Omit to leave unchanged; pass null to delete all provider overrides; pass an object to replace the full set.
      - DelayStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the Delay step.
          - DelayControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `type` 'regular' | 'timed', required: Type of the delay. Currently only 'regular' is supported by the schema.
            - `amount` number: Amount of time to delay.
            - `unit` 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months': Unit of time for the delay amount.
            - `cron` string: Cron expression for the delay. Min length 1.
          - object
      - DigestStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the Digest step.
          - DigestControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `type` 'regular' | 'timed': The type of digest strategy. Determines which fields are applicable.
            - `amount` number: The amount of time for the digest interval (for REGULAR type). Min 1.
            - `unit` 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months': The unit of time for the digest interval (for REGULAR type).
            - `lookBackWindow` LookBackWindowDto
              - …
            - `cron` string: Cron expression for TIMED digest. Min length 1.
            - `digestKey` string: Specify a custom key for digesting events instead of the default event key.
          - object
      - ThrottleStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the Throttle step.
          - ThrottleControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `type` 'fixed' | 'dynamic', required: The type of throttle window.
            - `amount` number: The amount of time for the throttle window (required for fixed type).
            - `unit` 'minutes' | 'hours' | 'days': The unit of time for the throttle window (required for fixed type).
            - `dynamicKey` string: Key path to retrieve dynamic window value (required for dynamic type).
            - `threshold` number: The maximum number of executions allowed within the window. Defaults to 1.
            - `throttleKey` string: Optional key for grouping throttle rules. If not provided, defaults to workflow and subscriber combination.
          - object
      - ToolStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the Tool step.
          - ToolControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `body` string: Content of the tool payload.
          - object
        - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`). Omit to leave unchanged; pass null to delete all provider overrides; pass an object to replace the full set.
      - CustomStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the Custom step.
          - CustomControlDto
            - `custom` object: Custom control values for the step.
          - object
      - HttpRequestStepUpsertDto
        - `_id` string: Database identifier of the step. Used for updating the step.
        - `stepId` string: Unique identifier for the step
        - `name` string, required: Name of the step
        - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
        - `controlValues` union: Control values for the HTTP Request step.
          - HttpRequestControlDto
            - `method` 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH', required: HTTP method
            - `url` string, required: Target URL for the HTTP request
            - `headers` HttpRequestKeyValuePairDto[]: Request headers as key-value pairs
              - …
            - `body` union: Request body as a raw JSON string. Key-value arrays are supported for legacy workflows.
              - …
            - `responseBodySchema` object: JSON schema to validate response body against
            - `enforceSchemaValidation` boolean: Whether to enforce response body schema validation
            - `continueOnFailure` boolean: Whether to continue workflow execution on failure
          - object
  - `__source` 'template_store' | 'editor' | 'notification_directory' | 'onboarding_digest_demo' | 'onboarding_in_app' | 'empty_state' | 'dropdown' | 'onboarding_get_started' | 'bridge' | 'dashboard' | 'ai': Source of workflow creation
  - `preferences` PreferencesRequestDto
    - `user` WorkflowPreferencesDto
      - `all` WorkflowPreferenceDto, required
        - `enabled` boolean, required: A flag specifying if notification delivery is enabled for the workflow. If true, notification delivery is enabled by default for all channels. This setting can be overridden by the channel preferences.
        - `readOnly` boolean, required: A flag specifying if the preference is read-only. If true, the preference cannot be changed by the Subscriber.
      - `channels` object, required: Preferences for different communication channels
    - `workflow` WorkflowPreferencesDto
      - `all` WorkflowPreferenceDto, required
        - `enabled` boolean, required: A flag specifying if notification delivery is enabled for the workflow. If true, notification delivery is enabled by default for all channels. This setting can be overridden by the channel preferences.
        - `readOnly` boolean, required: A flag specifying if the preference is read-only. If true, the preference cannot be changed by the Subscriber.
      - `channels` object, required: Preferences for different communication channels
  - `severity` 'high' | 'medium' | 'low' | 'none': Severity of the workflow

## Response `201`

Created

- object
  - `data` WorkflowResponseDto
    - `name` string, required: Name of the workflow
    - `description` string: Description of the workflow
    - `tags` string[]: Tags associated with the workflow
    - `active` boolean: Whether the workflow is active
    - `validatePayload` boolean: Enable or disable payload schema validation
    - `payloadSchema` object, nullable: The payload JSON Schema for the workflow
    - `isTranslationEnabled` boolean: Enable or disable translations for this workflow
    - `agent` WorkflowAgentConfigDto
      - `identifier` string, required: Public agent identifier used to route this workflow through an agent's connected channels.
      - `providers` object: Optional per-provider overrides keyed by providerId (e.g. novu-email-agent). Today only Novu Email replyTo is supported.
    - `_id` string, required: Database identifier of the workflow
    - `workflowId` string, required: Workflow identifier
    - `slug` string, required: Slug of the workflow
    - `updatedAt` string, required: Last updated timestamp
    - `createdAt` string, required: Creation timestamp
    - `updatedBy` UserResponseDto
      - `_id` string, required: User ID
      - `firstName` string, nullable: User first name
      - `lastName` string, nullable: User last name
      - `externalId` string, nullable: User external ID
    - `lastPublishedAt` string, nullable: Timestamp of the last workflow publication
    - `lastPublishedBy` UserResponseDto
      - `_id` string, required: User ID
      - `firstName` string, nullable: User first name
      - `lastName` string, nullable: User last name
      - `externalId` string, nullable: User external ID
    - `steps` union[], required: Steps of the workflow
      - union
        - InAppStepResponseDto
          - `controls` InAppControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` InAppControlDto, required
              - …
          - `controlValues` InAppControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `body` string: Content/body of the in-app message. Required if subject is empty.
            - `subject` string: Subject/title of the in-app message. Required if body is empty.
            - `avatar` string: URL for an avatar image. Must be a valid URL or start with / or {{ variable }}.
            - `primaryAction` ActionDto
              - …
            - `secondaryAction` ActionDto
              - …
            - `redirect` RedirectDto
              - …
            - `disableOutputSanitization` boolean: Disable sanitization of the output.
            - `data` object: Additional data payload for the step.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - EmailStepResponseDto
          - `controls` EmailControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` EmailControlDto, required
              - …
          - `controlValues` EmailControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `subject` string, required: Subject of the email.
            - `body` string, required: Body content of the email, either a valid Maily JSON object, or html string.
            - `editorType` 'block' | 'html': Type of editor to use for the body.
            - `disableOutputSanitization` boolean: Disable sanitization of the output.
            - `layoutId` string, nullable: Layout ID to use for the email. Null means no layout, undefined means default layout.
            - `from` EmailFromControlDto
              - …
            - `useProviderDefaults` boolean: When true, sender name/email use the primary email integration defaults and skip workflow agent defaults.
            - `replyTo` string: Step-level Reply-To override. When unset, inherits the workflow agent reply-to.
            - `preheader` string: One-line inbox preview text shown next to the subject.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - SmsStepResponseDto
          - `controls` SmsControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` SmsControlDto, required
              - …
          - `controlValues` SmsControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `body` string: Content of the SMS message.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - PushStepResponseDto
          - `controls` PushControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` PushControlDto, required
              - …
          - `controlValues` PushControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `subject` string: Subject/title of the push notification.
            - `body` string: Body content of the push notification.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - ChatStepResponseDto
          - `controls` ChatControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` ChatControlDto, required
              - …
          - `controlValues` ChatControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `body` string: Content of the chat message.
            - `editorType` 'block' | 'text': Type of editor to use for the body. When omitted, inferred from the body: Maily JSON is "block", otherwise "text".
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - DelayStepResponseDto
          - `controls` DelayControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` DelayControlDto, required
              - …
          - `controlValues` DelayControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `type` 'regular' | 'timed', required: Type of the delay. Currently only 'regular' is supported by the schema.
            - `amount` number: Amount of time to delay.
            - `unit` 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months': Unit of time for the delay amount.
            - `cron` string: Cron expression for the delay. Min length 1.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - DigestStepResponseDto
          - `controls` DigestControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` DigestControlDto, required
              - …
          - `controlValues` DigestControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `type` 'regular' | 'timed': The type of digest strategy. Determines which fields are applicable.
            - `amount` number: The amount of time for the digest interval (for REGULAR type). Min 1.
            - `unit` 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months': The unit of time for the digest interval (for REGULAR type).
            - `lookBackWindow` LookBackWindowDto
              - …
            - `cron` string: Cron expression for TIMED digest. Min length 1.
            - `digestKey` string: Specify a custom key for digesting events instead of the default event key.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - CustomStepResponseDto
          - `controls` CustomControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` CustomControlDto, required
              - …
          - `controlValues` CustomControlDto
            - `custom` object: Custom control values for the step.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - ThrottleStepResponseDto
          - `controls` ThrottleControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` ThrottleControlDto, required
              - …
          - `controlValues` ThrottleControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `type` 'fixed' | 'dynamic', required: The type of throttle window.
            - `amount` number: The amount of time for the throttle window (required for fixed type).
            - `unit` 'minutes' | 'hours' | 'days': The unit of time for the throttle window (required for fixed type).
            - `dynamicKey` string: Key path to retrieve dynamic window value (required for dynamic type).
            - `threshold` number: The maximum number of executions allowed within the window. Defaults to 1.
            - `throttleKey` string: Optional key for grouping throttle rules. If not provided, defaults to workflow and subscriber combination.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - HttpRequestStepResponseDto
          - `controls` HttpRequestControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` HttpRequestControlDto, required
              - …
          - `controlValues` HttpRequestControlDto
            - `method` 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH', required: HTTP method
            - `url` string, required: Target URL for the HTTP request
            - `headers` HttpRequestKeyValuePairDto[]: Request headers as key-value pairs
              - …
            - `body` union: Request body as a raw JSON string. Key-value arrays are supported for legacy workflows.
              - …
            - `responseBodySchema` object: JSON schema to validate response body against
            - `enforceSchemaValidation` boolean: Whether to enforce response body schema validation
            - `continueOnFailure` boolean: Whether to continue workflow execution on failure
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
        - ToolStepResponseDto
          - `controls` ToolControlsMetadataResponseDto, required
            - `dataSchema` object: JSON Schema for data
            - `uiSchema` UiSchema
              - …
            - `values` ToolControlDto, required
              - …
          - `controlValues` ToolControlDto
            - `skip` object: JSONLogic filter conditions for conditionally skipping the step execution. Supports complex logical operations with AND, OR, and comparison operators. See https://jsonlogic.com/ for full typing reference.
            - `body` string: Content of the tool payload.
          - `providerOverrides` object, nullable: Per-provider content overrides keyed by providerId. Stored separately from controlValues and merged over the default body at send time. Keys are ChatProviderIdEnum / ToolProviderIdEnum values (e.g. `slack`, `whatsapp-business`, `pagerduty`).
          - `variables` object, required: JSON Schema for variables, follows the JSON Schema standard
          - `stepId` string, required: Unique identifier of the step
          - `_id` string, required: Database identifier of the step
          - `name` string, required: Name of the step
          - `slug` string, required: Slug of the step
          - `type` 'in_app' | 'email' | 'sms' | 'chat' | 'push' | 'tool' | 'digest' | 'trigger' | 'delay' | 'throttle' | 'custom' | 'http_request', required: Type of the step
          - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
          - `workflowId` string, required: Workflow identifier
          - `workflowDatabaseId` string, required: Workflow database identifier
          - `issues` StepIssuesDto
            - `controls` object: Controls-related issues
            - `integration` object: Integration-related issues
          - `stepResolverHash` string: Hash identifying the deployed Cloudflare Worker for this step
    - `origin` 'novu-cloud' | 'novu-cloud-v1' | 'external', required: Origin of the layout
    - `preferences` WorkflowPreferencesResponseDto, required
      - `user` WorkflowPreferencesDto
        - `all` WorkflowPreferenceDto, required
          - `enabled` boolean, required: A flag specifying if notification delivery is enabled for the workflow. If true, notification delivery is enabled by default for all channels. This setting can be overridden by the channel preferences.
          - `readOnly` boolean, required: A flag specifying if the preference is read-only. If true, the preference cannot be changed by the Subscriber.
        - `channels` object, required: Preferences for different communication channels
      - `default` WorkflowPreferencesDto, required
        - `all` WorkflowPreferenceDto, required
          - `enabled` boolean, required: A flag specifying if notification delivery is enabled for the workflow. If true, notification delivery is enabled by default for all channels. This setting can be overridden by the channel preferences.
          - `readOnly` boolean, required: A flag specifying if the preference is read-only. If true, the preference cannot be changed by the Subscriber.
        - `channels` object, required: Preferences for different communication channels
    - `status` 'ACTIVE' | 'INACTIVE' | 'ERROR', required: Status of the workflow
    - `issues` object: Runtime issues for workflow creation and update
    - `lastTriggeredAt` string, nullable: Timestamp of the last workflow trigger
    - `payloadExample` object, nullable: Generated payload example based on the payload schema
    - `severity` 'high' | 'medium' | 'low' | 'none', required: Severity of the workflow

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found
- `405`: Method Not Allowed
- `409`: Conflict
- `413`: Payload Too Large
- `414`: URI Too Long
- `415`: Unsupported Media Type
- `422`: Unprocessable Entity
- `429`: The client has sent too many requests in a given amount of time.
- `500`: Internal Server Error
- `503`: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay.

---

[API](https://skmtc.dev/notifly/apis/notifly-api.md) · [All operations](https://skmtc.dev/notifly/apis/notifly-api/llms.txt) · [OpenAPI document](https://skmtc.dev/notifly/apis/notifly-api/revisions/af909b9e1e57?raw)
