A/B Tests
Create A/B Test
Create a campaign A/B test
POST
/
api
/
v1
/
ab-tests
Create A/B Test
curl --request POST \
--url https://api.sequenzy.com/api/v1/ab-tests \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"campaignId": "<string>",
"automationNodeId": "<string>",
"confirmLiveChange": true,
"name": "<string>",
"testPercentage": 123,
"testDurationMinutes": 123,
"winnerCriteria": "<string>",
"testType": "<string>",
"winnerThreshold": 123,
"variants": [
{}
]
}
'import requests
url = "https://api.sequenzy.com/api/v1/ab-tests"
payload = {
"campaignId": "<string>",
"automationNodeId": "<string>",
"confirmLiveChange": True,
"name": "<string>",
"testPercentage": 123,
"testDurationMinutes": 123,
"winnerCriteria": "<string>",
"testType": "<string>",
"winnerThreshold": 123,
"variants": [{}]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
campaignId: '<string>',
automationNodeId: '<string>',
confirmLiveChange: true,
name: '<string>',
testPercentage: 123,
testDurationMinutes: 123,
winnerCriteria: '<string>',
testType: '<string>',
winnerThreshold: 123,
variants: [{}]
})
};
fetch('https://api.sequenzy.com/api/v1/ab-tests', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sequenzy.com/api/v1/ab-tests",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'campaignId' => '<string>',
'automationNodeId' => '<string>',
'confirmLiveChange' => true,
'name' => '<string>',
'testPercentage' => 123,
'testDurationMinutes' => 123,
'winnerCriteria' => '<string>',
'testType' => '<string>',
'winnerThreshold' => 123,
'variants' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sequenzy.com/api/v1/ab-tests"
payload := strings.NewReader("{\n \"campaignId\": \"<string>\",\n \"automationNodeId\": \"<string>\",\n \"confirmLiveChange\": true,\n \"name\": \"<string>\",\n \"testPercentage\": 123,\n \"testDurationMinutes\": 123,\n \"winnerCriteria\": \"<string>\",\n \"testType\": \"<string>\",\n \"winnerThreshold\": 123,\n \"variants\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sequenzy.com/api/v1/ab-tests")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"campaignId\": \"<string>\",\n \"automationNodeId\": \"<string>\",\n \"confirmLiveChange\": true,\n \"name\": \"<string>\",\n \"testPercentage\": 123,\n \"testDurationMinutes\": 123,\n \"winnerCriteria\": \"<string>\",\n \"testType\": \"<string>\",\n \"winnerThreshold\": 123,\n \"variants\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sequenzy.com/api/v1/ab-tests")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"campaignId\": \"<string>\",\n \"automationNodeId\": \"<string>\",\n \"confirmLiveChange\": true,\n \"name\": \"<string>\",\n \"testPercentage\": 123,\n \"testDurationMinutes\": 123,\n \"winnerCriteria\": \"<string>\",\n \"testType\": \"<string>\",\n \"winnerThreshold\": 123,\n \"variants\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"abTest": {
"id": "ab_abc123",
"kind": "campaign",
"campaignId": "camp_abc123",
"name": "A/B Test for April Launch",
"status": "draft",
"testPercentage": 20,
"testDurationMinutes": 240,
"winnerCriteria": "open_rate",
"settings": {
"testPercentage": 20,
"testDurationMinutes": 240,
"winnerCriteria": "open_rate"
},
"variants": [
{ "id": "var_a", "label": "A", "subject": "A quick update" },
{ "id": "var_b", "label": "B", "subject": "Alternative subject line" }
]
}
}
{
"success": false,
"error": "testPercentage must be between 5 and 50"
}
{
"success": false,
"error": "Campaign structure can only be changed in draft or rejected status."
}
{
"success": false,
"error": "Maximum of 5 variants allowed"
}
{
"success": false,
"error": "Unauthorized"
}
{
"success": false,
"error": "Campaign not found"
}
{
"success": false,
"error": "A/B test already exists for this campaign"
}
{
"success": false,
"error": "Failed to create A/B test"
}
Create a draft A/B test for a campaign in
For a sequence test, copy the effective values from the source test’s
draft or rejected status, or convert a sequence email node into an A/B test step. Provide exactly one of campaignId or automationNodeId. Variant A (the control) is copied from the current email. A campaign or sequence node can have only one A/B test.
Request
string
Campaign to attach the test to. Must be in
draft or rejected status.
Mutually exclusive with automationNodeId.string
Sequence
action_email node to convert into an action_ab_test step.
Mutually exclusive with campaignId. Requires at least one variants entry.boolean
Required as
true when automationNodeId belongs to an active sequence. This
acknowledges that the live sequence graph will change immediately.string
Test name. Defaults to
A/B Test for <campaign name>.number
Campaign-only share of the audience that receives test sends. Must be from 5
to 50. Defaults to 20. Sequence tests use
winnerThreshold instead.number
Campaign-only duration before a winner is selected. Must be from 15 to 1440
minutes. Defaults to 240.
string
Metric used to pick the winner:
open_rate or click_rate. Campaigns default
to open_rate. For sequence tests, an explicit value overrides the testType
default.string
Sequence variant strategy:
subject or content. Subject defaults to
open_rate and content defaults to click_rate unless winnerCriteria is
explicit. Defaults to content. Sequence tests only.number
Number of sequence recipients in the test sample, from 10 to 1000. Defaults to
100. Sequence tests only.
array
Extra variants beyond the control. Each item takes
subject (required),
previewText, and blocks. Total variants cannot exceed 5. Variants without
blocks reuse the current email body. Optional for campaign tests; sequence
conversions require at least one entry.curl -X POST "https://api.sequenzy.com/api/v1/ab-tests" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaignId": "camp_abc123",
"testPercentage": 20,
"winnerCriteria": "open_rate",
"variants": [{ "subject": "Alternative subject line" }]
}'
settings object:
curl -X POST "https://api.sequenzy.com/api/v1/ab-tests" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"automationNodeId": "node_abc123",
"testType": "content",
"winnerCriteria": "open_rate",
"winnerThreshold": 150,
"variants": [{ "subject": "Alternative subject line" }]
}'
Responses
{
"success": true,
"abTest": {
"id": "ab_abc123",
"kind": "campaign",
"campaignId": "camp_abc123",
"name": "A/B Test for April Launch",
"status": "draft",
"testPercentage": 20,
"testDurationMinutes": 240,
"winnerCriteria": "open_rate",
"settings": {
"testPercentage": 20,
"testDurationMinutes": 240,
"winnerCriteria": "open_rate"
},
"variants": [
{ "id": "var_a", "label": "A", "subject": "A quick update" },
{ "id": "var_b", "label": "B", "subject": "Alternative subject line" }
]
}
}
{
"success": false,
"error": "testPercentage must be between 5 and 50"
}
{
"success": false,
"error": "Campaign structure can only be changed in draft or rejected status."
}
{
"success": false,
"error": "Maximum of 5 variants allowed"
}
{
"success": false,
"error": "Unauthorized"
}
{
"success": false,
"error": "Campaign not found"
}
{
"success": false,
"error": "A/B test already exists for this campaign"
}
{
"success": false,
"error": "Failed to create A/B test"
}
⌘I
Create A/B Test
curl --request POST \
--url https://api.sequenzy.com/api/v1/ab-tests \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"campaignId": "<string>",
"automationNodeId": "<string>",
"confirmLiveChange": true,
"name": "<string>",
"testPercentage": 123,
"testDurationMinutes": 123,
"winnerCriteria": "<string>",
"testType": "<string>",
"winnerThreshold": 123,
"variants": [
{}
]
}
'import requests
url = "https://api.sequenzy.com/api/v1/ab-tests"
payload = {
"campaignId": "<string>",
"automationNodeId": "<string>",
"confirmLiveChange": True,
"name": "<string>",
"testPercentage": 123,
"testDurationMinutes": 123,
"winnerCriteria": "<string>",
"testType": "<string>",
"winnerThreshold": 123,
"variants": [{}]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
campaignId: '<string>',
automationNodeId: '<string>',
confirmLiveChange: true,
name: '<string>',
testPercentage: 123,
testDurationMinutes: 123,
winnerCriteria: '<string>',
testType: '<string>',
winnerThreshold: 123,
variants: [{}]
})
};
fetch('https://api.sequenzy.com/api/v1/ab-tests', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sequenzy.com/api/v1/ab-tests",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'campaignId' => '<string>',
'automationNodeId' => '<string>',
'confirmLiveChange' => true,
'name' => '<string>',
'testPercentage' => 123,
'testDurationMinutes' => 123,
'winnerCriteria' => '<string>',
'testType' => '<string>',
'winnerThreshold' => 123,
'variants' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sequenzy.com/api/v1/ab-tests"
payload := strings.NewReader("{\n \"campaignId\": \"<string>\",\n \"automationNodeId\": \"<string>\",\n \"confirmLiveChange\": true,\n \"name\": \"<string>\",\n \"testPercentage\": 123,\n \"testDurationMinutes\": 123,\n \"winnerCriteria\": \"<string>\",\n \"testType\": \"<string>\",\n \"winnerThreshold\": 123,\n \"variants\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sequenzy.com/api/v1/ab-tests")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"campaignId\": \"<string>\",\n \"automationNodeId\": \"<string>\",\n \"confirmLiveChange\": true,\n \"name\": \"<string>\",\n \"testPercentage\": 123,\n \"testDurationMinutes\": 123,\n \"winnerCriteria\": \"<string>\",\n \"testType\": \"<string>\",\n \"winnerThreshold\": 123,\n \"variants\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sequenzy.com/api/v1/ab-tests")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"campaignId\": \"<string>\",\n \"automationNodeId\": \"<string>\",\n \"confirmLiveChange\": true,\n \"name\": \"<string>\",\n \"testPercentage\": 123,\n \"testDurationMinutes\": 123,\n \"winnerCriteria\": \"<string>\",\n \"testType\": \"<string>\",\n \"winnerThreshold\": 123,\n \"variants\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"abTest": {
"id": "ab_abc123",
"kind": "campaign",
"campaignId": "camp_abc123",
"name": "A/B Test for April Launch",
"status": "draft",
"testPercentage": 20,
"testDurationMinutes": 240,
"winnerCriteria": "open_rate",
"settings": {
"testPercentage": 20,
"testDurationMinutes": 240,
"winnerCriteria": "open_rate"
},
"variants": [
{ "id": "var_a", "label": "A", "subject": "A quick update" },
{ "id": "var_b", "label": "B", "subject": "Alternative subject line" }
]
}
}
{
"success": false,
"error": "testPercentage must be between 5 and 50"
}
{
"success": false,
"error": "Campaign structure can only be changed in draft or rejected status."
}
{
"success": false,
"error": "Maximum of 5 variants allowed"
}
{
"success": false,
"error": "Unauthorized"
}
{
"success": false,
"error": "Campaign not found"
}
{
"success": false,
"error": "A/B test already exists for this campaign"
}
{
"success": false,
"error": "Failed to create A/B test"
}