---
title: "Create sequence"
method: POST
path: "/sequences"
tags: ["Sequences"]
---

# Create sequence

`POST /sequences`

Creates a draft automation sequence using AI-generated content, explicit email/action steps, or a blank trigger-to-completion graph when both are omitted. Discount action steps dynamically generate Stripe or Shopify codes that later emails can reference with discount merge tags.

## Request body

- SequenceCreateRequest
  - `description` string — Optional dashboard description.
  - `userCancellable` boolean — Whether recipients can cancel this sequence from email preferences.
  - `labels` string[] — Dashboard label names. Missing labels are created.
  - `bccEmails` string[], nullable — Addresses blind-copied on every sequence email.
  - `fromEmail` string, email — From address for every email in this sequence. Its domain must be configured and verified.
  - `fromName` string — Display name recipients see, e.g. 'Brennon at TradeTally'. Selects the sender identity of that name on fromEmail, creating it when the address has no identity by that name; the mailbox's other display names, and everything pinned to them, are untouched. Requires fromEmail; omit it when using senderProfileId, which already carries its own display name.
  - `senderProfileId` string — Existing sender profile ID. It already supplies both the From address and display name, so send it on its own and omit fromEmail and fromName.
  - `replyTo` string, email — Reply-To address for every email in this sequence. A profile is created when needed.
  - `replyToName` string — Display name for the Reply-To address. Requires replyTo; omit it when using replyProfileId, which already carries its own display name. An address carries one Reply-To name company-wide, so if replyTo already has a saved profile under a different name, that saved name is kept and the response `warnings` array says so.
  - `replyProfileId` string — Existing reply profile ID. It already supplies both the Reply-To address and display name, so send it on its own and omit replyTo and replyToName.
  - `name` string, required
  - `trigger` 'contact_added' | 'tag_added' | 'segment_entered' | 'event_received' | 'inbound_webhook' | 'inactivity' | 'frequency'
  - `listId` string — List ID for contact_added triggers. If omitted, contact_added can match any list.
  - `tagName` string — Tag name for tag_added triggers.
  - `segmentId` string — Segment ID for segment_entered triggers.
  - `stopOnSegmentExit` boolean — For segment_entered triggers, cancel enrollment when the subscriber leaves the segment.
  - `eventName` string — Event name for event_received, inbound_webhook, inactivity, and frequency triggers.
  - `integrationSlug` string — Integration slug for inbound_webhook triggers.
  - `integrationEventKey` string — Integration event key for inbound_webhook triggers.
  - `customIntegration` object — Custom inbound-webhook integration metadata.
  - `propertyFilters` SequenceTriggerPropertyFilter[] — Event property filters for event_received and inbound_webhook triggers. The sequence only starts when the triggering event's properties match all filters. Use [] in the path to match items inside arrays.
    - `path` string, required — Dot-path into the event properties. Use [] to match items inside arrays.
    - `operator` 'exists' | 'not_exists' | 'equals' | 'not_equals' | 'one_of' | 'contains' | 'greater_than' | 'less_than', required — Comparison operator. Value is required for every operator except exists and not_exists. `one_of` matches when the property equals any entry of the value array.
    - `value` union — Value to compare against. For `one_of`, pass a non-empty array of strings or numbers (maximum 50 values); all other operators take a single value.
      - string
      - number
      - boolean
      - union[]
        - union
          - string
          - number
  - `inactiveDays` number — Days of inactivity before the sequence starts.
  - `inactivityBaseline` 'sequence_created_at' | 'subscriber_created_at' — For inactivity triggers, controls when to start counting for subscribers who have never performed the event. Defaults to sequence_created_at.
  - `minCount` number — Minimum event count for frequency triggers.
  - `timeWindowDays` number — Time window in days for frequency triggers.
  - `enrollmentMode` 'unlimited' | 'one_time' | 'matching_field' — Controls sequence re-entry. `unlimited` allows re-entry after completion but prevents concurrent active runs. `one_time` allows one enrollment ever. `matching_field` is only valid for event-triggered sequences and allows concurrent active runs only when the trigger payload resolves to a different event field value.
  - `enrollmentFieldPath` string — Scalar dot-path event property used by matching_field enrollment, such as order.id or product.providerVariantId. Array traversal with [] is not supported; use propertyFilters for array matching. Applies to event_received and inbound_webhook triggers. Leave empty for built-in Shopify product/variant defaults.
  - `sendingWindow` SequenceSendingWindow — Optional local-time sending window applied to every email step in a sequence. Email steps that become due outside the window wait until the next allowed local time.
    - `enabled` boolean
    - `timezone` string — IANA timezone for the window.
    - `startTime` string — Earliest local send time in 24-hour HH:mm format.
    - `endTime` string — Latest local send cutoff in 24-hour HH:mm format. Must be later than startTime.
    - `days` string[] — Allowed local days. Omit days when creating or updating to allow every day.
  - `emailCount` number — Number of emails for AI-generated content. Defaults to 5. Maximum is 10.
  - `durationDays` number — Total duration in days used to space AI-generated emails. Omit this to use the default sequence delay schedule.
  - `emailStyle` 'visual' | 'plain' — Style for the AI-generated emails: visual (designed, with heroes/imagery/rich sections) or plain (personal, text-first notes with a single button). Defaults to the company's saved preference when omitted.
  - `goal` string — Goal for AI-generated sequence content. Provide either goal or steps, or omit both for a blank dashboard-compatible draft.
  - `stopCondition` SequenceStopCondition — Auto-stop condition, re-evaluated before every step including the first one. has_tag, added_to_list, entered_segment, field_changed, and event_received stop the run once the thing happens. does_not_have_tag and removed_from_list stop the run whenever the subscriber lacks that tag or list membership, so they act as a required-tag or required-list allowlist and cancel everyone else before any step sends. Guarded-out contacts still enroll and are then cancelled at the trigger node, so they appear as cancellations there rather than in the active or waiting enrollment counts. Clearing the guard does not retry them: they only receive the sequence if the trigger fires for them again, and on the one_time enrollment mode not even then.
    - `type` 'none' | 'has_tag' | 'does_not_have_tag' | 'added_to_list' | 'removed_from_list' | 'entered_segment' | 'field_changed' | 'event_received'
    - `value` string, nullable — Tag name, list ID, segment ID, field path, or event name. For the does_not_have_tag and removed_from_list guards this is the tag or list a subscriber must have to keep receiving the sequence.
    - `matchConfig` union — Optional typed match rule. event_received uses event_property rules; field_changed uses a field_value comparison.
      - object
        - `mode` 'event_property', required
        - `rules` object[], required
          - `entryFieldPath` string, required
          - `eventFieldPath` string, required
      - object
        - `mode` 'field_value', required
        - `operator` 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'contains' | 'not_contains', required
        - `value` string, required
  - `steps` SequenceStepInput[] — Explicit email and action steps. Provide either steps or goal, or omit both for a blank dashboard-compatible draft.
    - `type` 'email' | 'sms' | 'create_discount' | 'discount' | 'update_subscriber' — Step type. Omit or use email for email content; use sms for a native SMS step; use create_discount for a dynamic discount; use update_subscriber for an Update Subscriber action.
    - `nodeType` 'action_email' | 'action_sms' | 'action_create_discount' | 'action_update_attributes' — Internal node-type alias for clients that work with automation nodes. Use action_update_attributes with config for Update Subscriber steps.
    - `config` SubscriberUpdateConfig — Update Subscriber config. String values may use standalone trigger-event merge tags such as {{event.plan}}, {{event.amount}}, or {{event.active}}. Number and boolean values are coerced after resolution.
      - `label` string
      - `firstName` string, nullable
      - `lastName` string, nullable
      - `status` 'active' | 'unsubscribed' | 'bounced'
      - `customAttributeUpdates` object[]
        - `name` string, required
        - `value` union, required — Literal scalar, null to delete, or one standalone merge tag.
          - string
          - number
          - boolean
        - `valueType` 'text' | 'number' | 'boolean'
    - `subject` string — Email subject line for email steps.
    - `previewText` string — Optional email preview text.
    - `text` string — SMS steps only. Plain-text message body; merge tags like {{FIRST_NAME}} work. Do not include opt-out text or a brand prefix - Sequenzy adds both automatically at send time.
    - `imageUrls` string[] — SMS steps only. Up to 2 publicly reachable image URLs sent as MMS media.
    - `ineligibleAction` 'skip' | 'exit' — SMS steps only. skip (default) continues the sequence when the contact can't receive SMS; exit removes them from the sequence.
    - `blocks` EmailBlock[] — Structured Sequenzy email blocks. Provide either blocks or html. Put visual styling under styles; top-level style keys such as backgroundColor, backgroundOpacity, borderColor, borderWidth, and borderRadius are normalized into styles.
      - `id` string
      - `type` 'text' | 'html' | 'heading' | 'list' | 'button' | 'spacer' | 'divider' | 'image' | 'columns' | 'conditional-group' | 'repeat' | 'card' | 'cta' | 'social' | 'logo' | 'header' | 'footer' | 'video' | 'product' | 'discount-code' | 'code' | 'countdown' | 'hero' | 'testimonial' | 'gallery' | 'badge' | 'table' | 'features' | 'image-card' | 'pricing' | 'author' | 'article' | 'rating' | 'stats' | 'steps' | 'product-grid' | 'poll', required
      - `content` string — Content for text, html, and heading-like blocks.
      - `styles` object — Per-block visual styles. For compatibility, style fields such as backgroundColor, backgroundOpacity, borderColor, borderWidth, and borderRadius can also be supplied at the block top level and are normalized into this object.
        - `paddingTop` number
        - `paddingBottom` number
        - `paddingLeft` number
        - `paddingRight` number
        - `backgroundColor` string
        - `backgroundOpacity` number — Background opacity percentage from 0 to 100.
        - `textColor` string
        - `textAlign` 'left' | 'center' | 'right'
        - `borderRadius` number
        - `borderColor` string
        - `borderWidth` number
        - `bleed` boolean — Stretch the block edge-to-edge across the email container. Top-level blocks only.
      - `conditions` object[] — Optional per-block display rules. The block renders only when every rule matches. The same shape is used for a conditional-group block's top-level `conditions`.
        - `id` string, required
        - `field` 'variable' | 'attribute' | 'email' | 'firstName' | 'lastName', required — `variable` resolves a merge-tag path from the transactional send `variables` or an automation `event` payload (nested paths like `order.total` or `event.plan` work). `attribute` reads a stored subscriber attribute. `email`, `firstName`, and `lastName` read core subscriber fields.
        - `operator` 'is' | 'is_not' | 'contains' | 'not_contains' | 'gt' | 'gte' | 'lt' | 'lte' | 'is_empty' | 'is_not_empty', required
        - `value` string, required — For `variable` and `attribute`, use `name:value` - the part before the colon is the variable path or attribute name, and the part after it is the comparison value. For `email`, `firstName`, and `lastName`, provide the plain comparison string.
    - `html` string — Raw HTML preserved as one HTML block. Provide either html or blocks.
    - `isTransactional` boolean — Send this email without the marketing unsubscribe footer.
    - `senderProfileId` string — Existing sender profile override for this email step.
    - `fromEmail` string, email — From address used to create a sender profile for this email step. Mutually exclusive with senderProfileId.
    - `fromName` string — Display name override for this email step. Alone it only changes the visible name; with fromEmail it also names a newly created sender profile.
    - `replyProfileId` string — Existing reply profile override for this email step.
    - `replyTo` string, email — Reply-To address used to create a reply profile for this email step. Mutually exclusive with replyProfileId.
    - `replyToName` string — Display name for the step reply profile. Requires replyTo; omit it when using replyProfileId, which already carries its own display name.
    - `ccEmails` string[] — Addresses CC'd on this email step. Send an empty array to clear them.
    - `bccEmails` string[] — Addresses BCC'd on this email step in addition to sequence-level BCC. Send an empty array to clear them.
    - `attachments` UrlAttachment[] — URL-backed file attachments for this email step, fetched at send time. Event-triggered sequences may use {{event.*}} URL templates. Send an empty array to clear them.
      - `filename` string, required — Filename shown in the recipient's email client (including extension). Event merge tags are supported.
      - `path` string, required — Public HTTP(S) URL or an event-backed URL template such as {{event.file_url}}. The resolved URL is validated and fetched at send time.
    - `delay` SequenceDelayInput — Delay before this step runs. Use duration fields for fixed waits, or mode until_date with untilDateField for event/date-field waits.
      - `mode` 'duration' | 'until_date' — Delay mode. Defaults to duration.
      - `days` number
      - `hours` number
      - `minutes` number
      - `untilDateField` string — Event/subscriber date field path to wait until when mode is until_date.
      - `field` string — Alias for untilDateField.
      - `untilOffsetDirection` 'before' | 'after' — Whether the offset runs before or after the date field. Defaults to after.
      - `direction` 'before' | 'after' — Alias for untilOffsetDirection.
      - `untilMissingAction` 'continue' | 'exit' — What to do when the date field is missing or invalid. Defaults to continue.
      - `missingAction` 'continue' | 'exit' — Alias for untilMissingAction.
    - `waitUntil` SequenceWaitUntilInput — Wait until a date from the enrollment event/subscriber data, optionally offset before or after that date.
      - `field` string — Event/subscriber date field path to wait until.
      - `untilDateField` string — Alias for field.
      - `offset` SequenceDelayOffsetInput — Relative offset for a delay.
        - `days` number
        - `hours` number
        - `minutes` number
      - `days` number — Shorthand offset days when offset is omitted.
      - `hours` number — Shorthand offset hours when offset is omitted.
      - `minutes` number — Shorthand offset minutes when offset is omitted.
      - `direction` 'before' | 'after' — Whether the offset runs before or after the field date. Defaults to after.
      - `untilOffsetDirection` 'before' | 'after' — Alias for direction.
      - `missingAction` 'continue' | 'exit' — What to do when the date field is missing or invalid. Defaults to continue.
      - `untilMissingAction` 'continue' | 'exit' — Alias for missingAction.
    - `delayMs` number — Delay before this step in milliseconds. Prefer delay for human-authored requests; use delayMs when importing provider waits.
    - `name` string — Optional email template name for email steps.
    - `discount` SequenceDiscountInput — Discount configuration for dynamic create_discount steps.
      - `label` string — Builder label for discount steps.
      - `provider` 'stripe' | 'shopify' — Discount provider. Use stripe to dynamically create a Stripe coupon plus promotion code, or shopify to dynamically create a Shopify Admin discount code.
      - `discountType` 'percent' | 'amount' — Discount type for create_discount steps.
      - `percentOff` number — Percent discount. Required when discountType is percent.
      - `amountOff` number — Fixed discount amount in the smallest currency unit, for example 500 for $5. Required when discountType is amount.
      - `currency` string — ISO currency for fixed-amount discounts. Defaults to usd.
      - `duration` 'once' | 'forever' | 'repeating' — Discount duration. Defaults to once.
      - `durationInMonths` number — Required for repeating discounts.
      - `appliesToAllPlans` boolean — Whether the discount applies to all plans. Defaults to true.
      - `planIds` string[] — Provider product IDs when appliesToAllPlans is false. Stripe uses IDs like prod_abc123; Shopify accepts numeric product IDs or gid://shopify/Product/... IDs.
      - `codePrefix` string — Optional prefix for generated dynamic codes. The final code also includes a subscriber/token suffix.
      - `maxRedemptions` number — Maximum redemptions for each generated code. Use 1 for subscriber-specific codes.
      - `lockToSubscriber` boolean — Stripe-only. Restrict each generated promotion code to the matched subscriber's Stripe customer.
      - `expiresAt` string — Optional future expiration date or ISO timestamp. Mutually exclusive with expiresInHours.
      - `expiresInHours` number — Optional relative expiration in hours, resolved when each subscriber's code is created. Takes precedence over expiresAt.
      - `name` string — Optional display name for each dynamically generated provider discount.
    - `label` string — Legacy top-level builder label for discount steps. Prefer discount.label.
    - `provider` 'stripe' | 'shopify' — Legacy top-level discount provider. Prefer discount.provider. Supports stripe and shopify.
    - `discountType` 'percent' | 'amount' — Legacy top-level discount type. Prefer discount.discountType.
    - `percentOff` number — Percent discount. Required when discountType is percent.
    - `amountOff` number — Fixed discount amount in the smallest currency unit, for example 500 for $5. Required when discountType is amount.
    - `currency` string — ISO currency for fixed-amount discounts. Defaults to usd.
    - `duration` 'once' | 'forever' | 'repeating' — Discount duration. Defaults to once.
    - `durationInMonths` number — Required for repeating discounts.
    - `appliesToAllPlans` boolean — Whether the discount applies to all plans. Defaults to true.
    - `planIds` string[] — Provider product IDs when appliesToAllPlans is false. Stripe uses IDs like prod_abc123; Shopify accepts numeric product IDs or gid://shopify/Product/... IDs.
    - `codePrefix` string — Optional prefix for generated dynamic codes. The final code also includes a subscriber/token suffix.
    - `maxRedemptions` number — Maximum redemptions for each generated code. Use 1 for subscriber-specific codes.
    - `lockToSubscriber` boolean — Legacy top-level Stripe-only flag. Prefer discount.lockToSubscriber.
    - `expiresAt` string — Optional future expiration date or ISO timestamp. Mutually exclusive with expiresInHours.
    - `expiresInHours` number — Optional relative expiration in hours, resolved when each subscriber's code is created. Takes precedence over expiresAt.

## Response `200`

Sequence created successfully

- SequenceCreateResponse
  - `success` boolean
  - `message` string
  - `sequence` object
    - `id` string
    - `name` string
    - `status` 'draft' | 'active' | 'paused' | 'archived' — Stored lifecycle status. Do not read literally: a sequence can be active while enrollmentPaused blocks new subscribers. Branch on effectiveStatus instead.
    - `enrollmentPaused` boolean — Whether new enrollments are paused while current recipients continue.
    - `effectiveStatus` 'draft' | 'live' | 'enrollment_paused' | 'paused' | 'archived' — Resolved run state, and the single field to branch on. live accepts new subscribers and advances existing recipients; enrollment_paused advances existing recipients only; draft, paused, and archived do neither.
    - `acceptsNewEnrollments` boolean — Whether new subscribers can enter the sequence right now.
    - `processesExistingEnrollments` boolean — Whether subscribers already inside the sequence keep advancing and receiving steps.
    - `effectiveStatusSummary` string — One plain-language sentence describing the run state, safe to show a user verbatim.
    - `trigger` string
    - `emailCount` number
    - `discountCount` number
    - `subscriberUpdateCount` number
    - `nodeCount` number
    - `enrichmentStatus` string
    - `stopCondition` SequenceStopCondition — Auto-stop condition, re-evaluated before every step including the first one. has_tag, added_to_list, entered_segment, field_changed, and event_received stop the run once the thing happens. does_not_have_tag and removed_from_list stop the run whenever the subscriber lacks that tag or list membership, so they act as a required-tag or required-list allowlist and cancel everyone else before any step sends. Guarded-out contacts still enroll and are then cancelled at the trigger node, so they appear as cancellations there rather than in the active or waiting enrollment counts. Clearing the guard does not retry them: they only receive the sequence if the trigger fires for them again, and on the one_time enrollment mode not even then.
      - `type` 'none' | 'has_tag' | 'does_not_have_tag' | 'added_to_list' | 'removed_from_list' | 'entered_segment' | 'field_changed' | 'event_received'
      - `value` string, nullable — Tag name, list ID, segment ID, field path, or event name. For the does_not_have_tag and removed_from_list guards this is the tag or list a subscriber must have to keep receiving the sequence.
      - `matchConfig` union — Optional typed match rule. event_received uses event_property rules; field_changed uses a field_value comparison.
        - object
          - `mode` 'event_property', required
          - `rules` object[], required
            - `entryFieldPath` string, required
            - `eventFieldPath` string, required
        - object
          - `mode` 'field_value', required
          - `operator` 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'contains' | 'not_contains', required
          - `value` string, required
    - `sendingWindow` SequenceSendingWindow — Optional local-time sending window applied to every email step in a sequence. Email steps that become due outside the window wait until the next allowed local time.
      - `enabled` boolean
      - `timezone` string — IANA timezone for the window.
      - `startTime` string — Earliest local send time in 24-hour HH:mm format.
      - `endTime` string — Latest local send cutoff in 24-hour HH:mm format. Must be later than startTime.
      - `days` string[] — Allowed local days. Omit days when creating or updating to allow every day.
  - `warnings` string[] — Non-blocking advisories about a successful write. Present when an input was discarded or did not take effect as requested. This includes block fields that do not render as their names suggest, sequence email-step formatting restored on top of submitted blocks, and sender-identity conflicts such as a replyToName that differs from the saved profile. Each message identifies the affected input and gives recovery guidance. Absent when there is nothing to report.
  - `eventTrackingCode` string — Code snippet returned for custom event triggers.
  - `eventTracking` object — Endpoint, payload contract, example, documentation, and integration-guide pointer returned for custom event triggers.
    - `endpoint` string
    - `method` string
    - `docsUrl` string
    - `integrationGuide` object
      - `tool` string
      - `arguments` object
    - `payloadContract` object
      - `required` string[]
      - `identity` string
      - `event` string
      - `properties` string
      - `requiredPropertyPaths` string[]
      - `propertyFilters` SequenceTriggerPropertyFilter[] — Normalized trigger filters that the event properties must satisfy before the sequence can enroll the subscriber.
        - `path` string, required — Dot-path into the event properties. Use [] to match items inside arrays.
        - `operator` 'exists' | 'not_exists' | 'equals' | 'not_equals' | 'one_of' | 'contains' | 'greater_than' | 'less_than', required — Comparison operator. Value is required for every operator except exists and not_exists. `one_of` matches when the property equals any entry of the value array.
        - `value` union — Value to compare against. For `one_of`, pass a non-empty array of strings or numbers (maximum 50 values); all other operators take a single value.
          - string
          - number
          - boolean
          - union[]
            - union
              - …
    - `examplePayload` object
    - `examplePayloadMatchesFilters` boolean — Whether examplePayload already satisfies every normalized property filter. When false, adapt properties using payloadContract before sending the sample.
    - `examplePayloadNote` string — Present when the generated example needs manual property adaptation before it satisfies every filter.
  - `requiredEvents` string[]

## Other responses

- `400` — Validation error
- `401` — Unauthorized
- `403` — No company selected
- `500` — Internal server error

---

[API](https://skmtc.net/sequenzy/apis/sequenzy-api.md) · [All operations](https://skmtc.net/sequenzy/apis/sequenzy-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/sequenzy/sequenzy-api/versions/af1cf9620482/schema)
