A/B Test Design Variants API
Create and manage A/B tests with optional design variations for variant B.
Overview
PostBeagle's A/B testing feature allows you to test different subject lines, preview text, from names, and from emails. With design variants, you can also test different email designs for variant B.
By default, both variants share the same email design. You can optionally create a different design for variant B by cloning variant A's design or starting from scratch.
Create A/B Test with Design Variants
Create a new A/B test campaign with optional design configuration.
Endpoint
POST /api/ab-tests
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Campaign name (internal) |
variantA | object | Yes | Variant A configuration |
variantB | object | Yes | Variant B configuration |
testDuration | integer | Yes | Test duration in hours |
testPercentage | integer | Yes | Percentage of audience for test (1-99) |
winningMetric | string | Yes | Metric to determine winner: open_rate or click_rate |
hasDifferentDesign | boolean | No | Whether variant B uses a different design (default: false) |
variantB.body | string | No | HTML content for variant B (if different design) |
variantB.designBlocks | object | No | Block structure for variant B (if using new builder) |
variantB.editorType | string | No | Editor type: grapesjs or new-builder |
Variant Configuration
Each variant object contains:
| Field | Type | Required | Description |
|---|---|---|---|
subject | string | Yes | Email subject line |
previewText | string | No | Email preview text |
fromName | string | Yes | Sender name |
fromEmail | string | Yes | Verified sender email |
body | string | Yes (A only) | HTML email content |
designBlocks | object | No | Block structure (if using new builder) |
editorType | string | No | Editor type: grapesjs or new-builder |
Example Request - Same Design (Default)
curl -X POST "https://api.postbeagle.com/api/ab-tests" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Newsletter Subject Line Test",
"variantA": {
"subject": "Your Weekly Newsletter",
"previewText": "Check out this week'\''s updates",
"fromName": "PostBeagle Team",
"fromEmail": "[email protected]",
"body": "<html><body><h1>Newsletter</h1></body></html>",
"editorType": "grapesjs"
},
"variantB": {
"subject": "This Week'\''s Top Stories",
"previewText": "Don'\''t miss these updates",
"fromName": "PostBeagle Team",
"fromEmail": "[email protected]"
},
"testDuration": 24,
"testPercentage": 20,
"winningMetric": "open_rate",
"hasDifferentDesign": false
}'
Example Request - Different Design
curl -X POST "https://api.postbeagle.com/api/ab-tests" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Newsletter Design Test",
"variantA": {
"subject": "Your Weekly Newsletter",
"previewText": "Check out this week'\''s updates",
"fromName": "PostBeagle Team",
"fromEmail": "[email protected]",
"body": "<html><body><h1>Newsletter</h1></body></html>",
"editorType": "grapesjs"
},
"variantB": {
"subject": "Your Weekly Newsletter",
"previewText": "Check out this week'\''s updates",
"fromName": "PostBeagle Team",
"fromEmail": "[email protected]",
"body": "<html><body><h2>Newsletter</h2><p>Different layout</p></body></html>",
"editorType": "grapesjs"
},
"testDuration": 24,
"testPercentage": 20,
"winningMetric": "click_rate",
"hasDifferentDesign": true
}'
Example Response
{
"success": true,
"data": {
"id": "abtest_123",
"name": "Newsletter Subject Line Test",
"status": "draft",
"hasDifferentDesign": false,
"testDuration": 24,
"testPercentage": 20,
"winningMetric": "open_rate",
"created_at": "2025-11-29T10:00:00Z"
}
}
Clone Design to Variant B
Clone variant A's design to variant B as a starting point for editing.
Endpoint
POST /api/ab-tests/:id/clone-design
Example Request
curl -X POST "https://api.postbeagle.com/api/ab-tests/abtest_123/clone-design" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"
Example Response
{
"success": true,
"data": {
"variantB": {
"body": "<html><body><h1>Newsletter</h1></body></html>",
"designBlocks": null,
"editorType": "grapesjs"
}
}
}
Update Variant B Design
Update the design for variant B.
Endpoint
PUT /api/ab-tests/:id/variant-b-design
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
body | string | Yes | HTML email content |
designBlocks | object | No | Block structure (if using new builder) |
editorType | string | Yes | Editor type: grapesjs or new-builder |
Example Request
curl -X PUT "https://api.postbeagle.com/api/ab-tests/abtest_123/variant-b-design" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"body": "<html><body><h2>Updated Design</h2></body></html>",
"editorType": "grapesjs"
}'
Example Response
{
"success": true,
"data": {
"id": "abtest_123",
"hasDifferentDesign": true,
"variantB": {
"body": "<html><body><h2>Updated Design</h2></body></html>",
"editorType": "grapesjs"
}
}
}
Switch to Same Design
Switch variant B back to using variant A's design. This will delete variant B's design data.
Endpoint
POST /api/ab-tests/:id/use-same-design
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
confirmed | boolean | Yes | Must be true to confirm data deletion |
Example Request
curl -X POST "https://api.postbeagle.com/api/ab-tests/abtest_123/use-same-design" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"confirmed": true
}'
Example Response
{
"success": true,
"data": {
"id": "abtest_123",
"hasDifferentDesign": false
}
}
Get A/B Test with Design Data
Retrieve A/B test details including design configuration.
Endpoint
GET /api/ab-tests/:id
Example Response - Same Design
{
"success": true,
"data": {
"id": "abtest_123",
"name": "Newsletter Subject Line Test",
"status": "testing",
"hasDifferentDesign": false,
"variantA": {
"subject": "Your Weekly Newsletter",
"previewText": "Check out this week's updates",
"fromName": "PostBeagle Team",
"fromEmail": "[email protected]",
"body": "<html><body><h1>Newsletter</h1></body></html>",
"editorType": "grapesjs"
},
"variantB": {
"subject": "This Week's Top Stories",
"previewText": "Don't miss these updates",
"fromName": "PostBeagle Team",
"fromEmail": "[email protected]"
},
"testDuration": 24,
"testPercentage": 20,
"winningMetric": "open_rate",
"stats": {
"variantA": {
"sent": 100,
"opened": 35,
"clicked": 12,
"open_rate": 35.0,
"click_rate": 12.0
},
"variantB": {
"sent": 100,
"opened": 42,
"clicked": 15,
"open_rate": 42.0,
"click_rate": 15.0
}
},
"created_at": "2025-11-29T10:00:00Z",
"started_at": "2025-11-29T11:00:00Z"
}
}
Example Response - Different Design
{
"success": true,
"data": {
"id": "abtest_456",
"name": "Newsletter Design Test",
"status": "testing",
"hasDifferentDesign": true,
"variantA": {
"subject": "Your Weekly Newsletter",
"previewText": "Check out this week's updates",
"fromName": "PostBeagle Team",
"fromEmail": "[email protected]",
"body": "<html><body><h1>Newsletter</h1></body></html>",
"editorType": "grapesjs"
},
"variantB": {
"subject": "Your Weekly Newsletter",
"previewText": "Check out this week's updates",
"fromName": "PostBeagle Team",
"fromEmail": "[email protected]",
"body": "<html><body><h2>Newsletter</h2><p>Different layout</p></body></html>",
"editorType": "grapesjs"
},
"testDuration": 24,
"testPercentage": 20,
"winningMetric": "click_rate",
"stats": {
"variantA": {
"sent": 100,
"opened": 35,
"clicked": 12,
"open_rate": 35.0,
"click_rate": 12.0
},
"variantB": {
"sent": 100,
"opened": 38,
"clicked": 18,
"open_rate": 38.0,
"click_rate": 18.0
}
},
"created_at": "2025-11-29T10:00:00Z",
"started_at": "2025-11-29T11:00:00Z"
}
}
Error Responses
400 Bad Request - Missing Confirmation
{
"success": false,
"error": {
"code": "CONFIRMATION_REQUIRED",
"message": "You must confirm this action by setting confirmed=true"
}
}
403 Forbidden - Unauthorized
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "You do not have permission to modify this A/B test"
}
}
404 Not Found - A/B Test Not Found
{
"success": false,
"error": {
"code": "AB_TEST_NOT_FOUND",
"message": "A/B test not found"
}
}
409 Conflict - Already Sent
{
"success": false,
"error": {
"code": "ALREADY_SENT",
"message": "Cannot modify A/B test that has already been sent"
}
}
422 Unprocessable Entity - Invalid Design Data
{
"success": false,
"error": {
"code": "INVALID_DESIGN_DATA",
"message": "Design body is required when updating variant B design"
}
}
Code Examples
JavaScript - Create A/B Test with Different Designs
async function createABTestWithDesigns() {
const response = await fetch('https://api.postbeagle.com/api/ab-tests', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Design Variation Test',
variantA: {
subject: 'Your Weekly Newsletter',
previewText: 'Check out this week\'s updates',
fromName: 'PostBeagle Team',
fromEmail: '[email protected]',
body: '<html><body><h1>Newsletter</h1></body></html>',
editorType: 'grapesjs'
},
variantB: {
subject: 'Your Weekly Newsletter',
previewText: 'Check out this week\'s updates',
fromName: 'PostBeagle Team',
fromEmail: '[email protected]',
body: '<html><body><h2>Newsletter</h2><p>Different layout</p></body></html>',
editorType: 'grapesjs'
},
testDuration: 24,
testPercentage: 20,
winningMetric: 'click_rate',
hasDifferentDesign: true
})
});
return await response.json();
}
JavaScript - Clone and Update Design
async function cloneAndUpdateDesign(abTestId) {
// 1. Clone variant A's design to variant B
const cloneResponse = await fetch(
`https://api.postbeagle.com/api/ab-tests/${abTestId}/clone-design`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
}
);
const cloneData = await cloneResponse.json();
// 2. Modify the cloned design
const modifiedBody = cloneData.data.variantB.body.replace(
'<h1>Newsletter</h1>',
'<h2>Newsletter - Variant B</h2>'
);
// 3. Update variant B with modified design
const updateResponse = await fetch(
`https://api.postbeagle.com/api/ab-tests/${abTestId}/variant-b-design`,
{
method: 'PUT',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
body: modifiedBody,
editorType: 'grapesjs'
})
}
);
return await updateResponse.json();
}
Python - Create and Manage Design Variants
import requests
class ABTestDesignManager:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = 'https://api.postbeagle.com/api'
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
def create_ab_test(self, name, variant_a, variant_b,
test_duration, test_percentage,
winning_metric, has_different_design=False):
"""Create a new A/B test with optional design variants"""
url = f'{self.base_url}/ab-tests'
data = {
'name': name,
'variantA': variant_a,
'variantB': variant_b,
'testDuration': test_duration,
'testPercentage': test_percentage,
'winningMetric': winning_metric,
'hasDifferentDesign': has_different_design
}
response = requests.post(url, json=data, headers=self.headers)
return response.json()
def clone_design(self, ab_test_id):
"""Clone variant A's design to variant B"""
url = f'{self.base_url}/ab-tests/{ab_test_id}/clone-design'
response = requests.post(url, headers=self.headers)
return response.json()
def update_variant_b_design(self, ab_test_id, body,
editor_type, design_blocks=None):
"""Update variant B's design"""
url = f'{self.base_url}/ab-tests/{ab_test_id}/variant-b-design'
data = {
'body': body,
'editorType': editor_type
}
if design_blocks:
data['designBlocks'] = design_blocks
response = requests.put(url, json=data, headers=self.headers)
return response.json()
def use_same_design(self, ab_test_id):
"""Switch variant B to use variant A's design"""
url = f'{self.base_url}/ab-tests/{ab_test_id}/use-same-design'
data = {'confirmed': True}
response = requests.post(url, json=data, headers=self.headers)
return response.json()
# Usage example
manager = ABTestDesignManager('your_api_key')
# Create A/B test with same design
ab_test = manager.create_ab_test(
name='Subject Line Test',
variant_a={
'subject': 'Your Weekly Newsletter',
'fromName': 'PostBeagle Team',
'fromEmail': '[email protected]',
'body': '<html><body><h1>Newsletter</h1></body></html>',
'editorType': 'grapesjs'
},
variant_b={
'subject': 'This Week\'s Top Stories',
'fromName': 'PostBeagle Team',
'fromEmail': '[email protected]'
},
test_duration=24,
test_percentage=20,
winning_metric='open_rate',
has_different_design=False
)
# Clone and modify design
ab_test_id = ab_test['data']['id']
cloned = manager.clone_design(ab_test_id)
modified_body = cloned['data']['variantB']['body'].replace(
'<h1>Newsletter</h1>',
'<h2>Newsletter - Variant B</h2>'
)
manager.update_variant_b_design(ab_test_id, modified_body, 'grapesjs')
Best Practices
When to Use Design Variants
- Test Content Hierarchy: Compare different layouts or content organization
- Test Visual Elements: Compare different images, colors, or styling
- Test CTA Placement: Compare different call-to-action button positions
- Test Email Length: Compare short vs. long-form content
When to Use Same Design
- Subject Line Testing: Focus on subject line optimization
- From Name Testing: Test sender name variations
- Preview Text Testing: Optimize preview text
- Timing Tests: Test send times with identical content
Design Testing Tips
- One Variable at a Time: When testing designs, keep subject lines the same
- Significant Differences: Make design changes meaningful enough to measure
- Mobile Optimization: Ensure both designs work well on mobile devices
- Test Duration: Allow sufficient time for statistical significance
- Sample Size: Use larger test percentages for design tests (20-30%)
Storage Optimization
- Use
hasDifferentDesign: falsewhen variants share the same design - This avoids duplicating design data in the database
- The system automatically uses variant A's design for variant B
Editor Flexibility
- Variant A and variant B can use different editors (GrapesJS or new builder)
- The system uses the HTML output regardless of editor type
- Clone operations preserve the original editor type
Workflow Examples
Workflow 1: Subject Line Test (Same Design)
// 1. Create A/B test with same design
const abTest = await createABTest({
hasDifferentDesign: false,
variantA: { subject: 'Option A', body: '<html>...</html>' },
variantB: { subject: 'Option B' }
});
// 2. Send test
await sendABTest(abTest.data.id);
// 3. Check results
const results = await getABTestResults(abTest.data.id);
Workflow 2: Design Test (Clone and Modify)
// 1. Create A/B test with variant A design
const abTest = await createABTest({
hasDifferentDesign: false,
variantA: { subject: 'Newsletter', body: '<html>...</html>' },
variantB: { subject: 'Newsletter' }
});
// 2. Clone design to variant B
await cloneDesign(abTest.data.id);
// 3. Update variant B design
await updateVariantBDesign(abTest.data.id, {
body: '<html>...modified...</html>',
editorType: 'grapesjs'
});
// 4. Send test
await sendABTest(abTest.data.id);
Workflow 3: Design Test (From Scratch)
// 1. Create A/B test with both designs
const abTest = await createABTest({
hasDifferentDesign: true,
variantA: {
subject: 'Newsletter',
body: '<html>...design A...</html>',
editorType: 'grapesjs'
},
variantB: {
subject: 'Newsletter',
body: '<html>...design B...</html>',
editorType: 'new-builder'
}
});
// 2. Send test
await sendABTest(abTest.data.id);
Next Steps
- Campaigns API - Learn about campaign management
- Analytics API - Track A/B test performance
- Email Lists API - Manage your recipients