Documentation menu

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

FieldTypeRequiredDescription
namestringYesCampaign name (internal)
variantAobjectYesVariant A configuration
variantBobjectYesVariant B configuration
testDurationintegerYesTest duration in hours
testPercentageintegerYesPercentage of audience for test (1-99)
winningMetricstringYesMetric to determine winner: open_rate or click_rate
hasDifferentDesignbooleanNoWhether variant B uses a different design (default: false)
variantB.bodystringNoHTML content for variant B (if different design)
variantB.designBlocksobjectNoBlock structure for variant B (if using new builder)
variantB.editorTypestringNoEditor type: grapesjs or new-builder

Variant Configuration

Each variant object contains:

FieldTypeRequiredDescription
subjectstringYesEmail subject line
previewTextstringNoEmail preview text
fromNamestringYesSender name
fromEmailstringYesVerified sender email
bodystringYes (A only)HTML email content
designBlocksobjectNoBlock structure (if using new builder)
editorTypestringNoEditor 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

FieldTypeRequiredDescription
bodystringYesHTML email content
designBlocksobjectNoBlock structure (if using new builder)
editorTypestringYesEditor 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

FieldTypeRequiredDescription
confirmedbooleanYesMust 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

  1. Test Content Hierarchy: Compare different layouts or content organization
  2. Test Visual Elements: Compare different images, colors, or styling
  3. Test CTA Placement: Compare different call-to-action button positions
  4. Test Email Length: Compare short vs. long-form content

When to Use Same Design

  1. Subject Line Testing: Focus on subject line optimization
  2. From Name Testing: Test sender name variations
  3. Preview Text Testing: Optimize preview text
  4. Timing Tests: Test send times with identical content

Design Testing Tips

  1. One Variable at a Time: When testing designs, keep subject lines the same
  2. Significant Differences: Make design changes meaningful enough to measure
  3. Mobile Optimization: Ensure both designs work well on mobile devices
  4. Test Duration: Allow sufficient time for statistical significance
  5. Sample Size: Use larger test percentages for design tests (20-30%)

Storage Optimization

  • Use hasDifferentDesign: false when 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