---
title: "Create A/B test"
method: POST
path: "/ab-tests"
tags: ["A/B Tests"]
---

# Create A/B test

`POST /ab-tests`

Creates a draft campaign A/B test or converts a sequence email node to action_ab_test. Provide exactly one owner. Variant A is copied into an independent email for sequences; sequence conversions require at least one extra variant.

## Request body

- object
  - `campaignId` string — Campaign to attach the test to. Must be in draft or rejected status. Mutually exclusive with automationNodeId.
  - `automationNodeId` string — Sequence action_email node to convert. Mutually exclusive with campaignId.
  - `confirmLiveChange` boolean — Must be true when converting an email node in an active sequence.
  - `name` string — Test name. Defaults to "A/B Test for <campaign name>".
  - `testPercentage` integer — Campaign-only share of the audience that receives test sends. Sequence tests use winnerThreshold.
  - `testDurationMinutes` integer — Campaign-only duration before winner selection. Sequence tests select after winnerThreshold recipients.
  - `winnerCriteria` 'open_rate' | 'click_rate' — Metric used to pick the winner. For sequence tests, an explicit value overrides the testType default.
  - `testType` 'subject' | 'content' — Sequence variant strategy. Subject defaults to open_rate and content defaults to click_rate unless winnerCriteria is explicit.
  - `winnerThreshold` integer — Number of sequence recipients in the test sample.
  - `variants` object[] — Extra variants beyond the control. Required (min 1) when converting with automationNodeId. Total variants cannot exceed 5.
    - `subject` string, required
    - `previewText` string
    - `blocks` EmailBlock[]
      - `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.

## Response `200`

A/B test created

- object
  - `success` boolean
  - `abTest` ABTest
    - `id` string
    - `companyId` string
    - `kind` 'campaign' | 'sequence' — Identifies which settings model applies to this test.
    - `campaignId` string, nullable
    - `automationNodeId` string, nullable
    - `name` string, nullable
    - `status` string
    - `testPercentage` integer — Campaign test audience percentage. Sequence tests retain the legacy internal sentinel value 100; use settings instead.
    - `testDurationMinutes` integer — Campaign test duration. Sequence tests retain the legacy internal sentinel value 0; use settings instead.
    - `winnerCriteria` string
    - `testType` 'subject' | 'content' — Effective sequence variant strategy. Present for sequence tests.
    - `winnerThreshold` integer — Effective sequence recipient threshold. Present for sequence tests.
    - `settings` object — Effective settings for this test kind. Campaign tests return testPercentage, testDurationMinutes, and winnerCriteria; sequence tests return testType, winnerThreshold, and winnerCriteria.
    - `winningVariantId` string, nullable
    - `winnerSelectedAt` string, date-time, nullable
    - `testStartedAt` string, date-time, nullable
    - `testEndsAt` string, date-time, nullable
    - `createdAt` string, date-time
    - `updatedAt` string, date-time
    - `variants` ABTestVariant[]
      - `id` string
      - `variantId` string
      - `abTestId` string
      - `label` string
      - `variantLabel` string
      - `emailId` string
      - `subject` string
      - `previewText` string, nullable
      - `blocks` EmailBlock[]
        - `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.
      - `testSends` integer
      - `testOpens` integer
      - `testClicks` integer
      - `isWinner` boolean
      - `localizations` object[]
      - `createdAt` string, date-time
  - `warnings` string[] — Non-blocking advisories about the blocks that were written. The write succeeded. Present when a field was not part of the block schema and was discarded, or when a supported field does not control what its name suggests for that block type - for example styles.backgroundColor on a button colors the band behind the button while the fill comes from buttonColor. Each message names the offending path and the fields that block does accept. Absent when there is nothing to report.

## Other responses

- `400` — Validation error, invalid owner, or non-draft campaign
- `401` — Unauthorized
- `404` — Campaign, sequence node, or email not found
- `409` — A/B test already exists for this campaign or sequence node
- `500` — A/B test could not be created

## Changes

- **2026-07-29** `d03612b5fabd` — 1 info
  - added the optional property `warnings` to the response with the `200` status
- **2026-07-25** `b58891ac1cde` — 4 info
  - added the optional property `abTest/kind` to the response with the `200` status
  - added the optional property `abTest/settings` to the response with the `200` status
  - added the optional property `abTest/testType` to the response with the `200` status
  - added the optional property `abTest/winnerThreshold` to the response with the `200` status
- **2026-07-18** `09f0c32988fb` — 5 info
  - added the new optional request property `automationNodeId`
  - added the new optional request property `confirmLiveChange`
  - added the new optional request property `testType`
  - added the new optional request property `winnerThreshold`
  - …1 more
- **2026-07-16** `d7ea66dede72` — 14 warning, 16 info
  - added the new `article` enum value to the `abTest/variants/items/blocks/items/type` response property for the response status `200`
  - added the new `author` enum value to the `abTest/variants/items/blocks/items/type` response property for the response status `200`
  - added the new `badge` enum value to the `abTest/variants/items/blocks/items/type` response property for the response status `200`
  - added the new `features` enum value to the `abTest/variants/items/blocks/items/type` response property for the response status `200`
  - …26 more
- …earlier changes not shown

[Full history](https://skmtc.dev/sequenzy/apis/sequenzy-api/changes/ab-tests/post.md)

---

[API](https://skmtc.dev/sequenzy/apis/sequenzy-api.md) · [All operations](https://skmtc.dev/sequenzy/apis/sequenzy-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/sequenzy/sequenzy-api/revisions/6db218f95cf4/schema)
