A/B Tests

Create A/B test

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.

post/ab-tests

Request body

campaignIdstring

Campaign to attach the test to. Must be in draft or rejected status. Mutually exclusive with automationNodeId.

automationNodeIdstring

Sequence action_email node to convert. Mutually exclusive with campaignId.

confirmLiveChangeboolean

Must be true when converting an email node in an active sequence.

namestring

Test name. Defaults to "A/B Test for <campaign name>".

testPercentageinteger

Campaign-only share of the audience that receives test sends. Sequence tests use winnerThreshold.

testDurationMinutesinteger

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.

winnerThresholdinteger

Number of sequence recipients in the test sample.

Example request

{
  "variants": [
    {
      "blocks": [
        {
          "id": "block_123",
          "type": "html",
          "content": "<h1>Hello</h1>",
          "styles": {
            "backgroundColor": "#f8fafc",
            "backgroundOpacity": 80,
            "textColor": "#111827",
            "borderRadius": 12,
            "borderColor": "#cbd5e1",
            "borderWidth": 1
          },
          "conditions": [
            {
              "id": "c1",
              "value": "plan:pro"
            }
          ]
        }
      ]
    }
  ]
}

Response

A/B test created

successboolean
warningsstring[]

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.

Example response

{
  "success": true,
  "abTest": {
    "id": "ab_abc123",
    "companyId": "company_abc123",
    "campaignId": "camp_abc123",
    "automationNodeId": "node_abc123",
    "name": "Subject test",
    "status": "draft",
    "winnerCriteria": "open_rate",
    "variants": [
      {
        "id": "var_a",
        "variantId": "var_a",
        "abTestId": "ab_abc123",
        "label": "A",
        "variantLabel": "A",
        "emailId": "email_abc123",
        "subject": "Welcome",
        "blocks": [
          {
            "id": "block_123",
            "type": "html",
            "content": "<h1>Hello</h1>",
            "styles": {
              "backgroundColor": "#f8fafc",
              "backgroundOpacity": 80,
              "textColor": "#111827",
              "borderRadius": 12,
              "borderColor": "#cbd5e1",
              "borderWidth": 1
            },
            "conditions": [
              {
                "id": "c1",
                "value": "plan:pro"
              }
            ]
          }
        ]
      }
    ]
  },
  "warnings": [
    "blocks[0].styles.color is not a supported field and was ignored. Button label color comes from the block-level `buttonTextColor` field. Supported styles fields: backgroundColor, backgroundOpacity, bleed, borderColor, borderRadius, borderWidth, paddingBottom, paddingLeft, paddingRight, paddingTop, textAlign, textColor."
  ]
}

Changes