Marketing
Campaigns, A/B testing & migration
Run high-volume email campaigns with A/B split testing, dynamic audience segmentation, AI content generation, and 1-click Brevo workspace migration.
Portal endpoints under /api/v1/* are authenticated with a portal session (Authorization: Bearer <jwt>). You can also manage all of these features visually in the portal under Campaigns, Segments and Events & Brevo Import.
A/B split testing for campaigns
Any email campaign can include an ab_test configuration. When the campaign starts sending:
- SnappyMails takes a deterministic audience snapshot from your
list_ids,segment_idsandexclude_segment_ids. - The initial test sample (
sample_percent, between 10% and 50% of total recipients) is split evenly 50/50 between Variant A (the campaign's default subject, sender name and HTML) and Variant B (the overridden field). - Once the test sample finishes dispatching, the campaign enters
phase: "WAITING_WINNER"untilwinner_pick_at(test_hoursafter sample completion). - When the evaluation timer elapses (or when you crown a winner manually), SnappyMails compares Variant A and Variant B by
winner_criteria(open_rateorclick_rate), recordswinner_variantand automatically dispatches the winning variant to the remaining 50%โ90% of your audience.
/api/v1/campaignsBearer JWT| Parameter | Type | Description |
|---|---|---|
ab_test.enabledrequired | boolean | Enables A/B split testing on the campaign. |
ab_test.test_typerequired | string | What to test: subject (Subject Line), from_name (Sender Name) or content (Email HTML Content). |
ab_test.variant_b_subject | string | Variant B subject line (supports template tags). |
ab_test.variant_b_from_name | string | Variant B sender display name. |
ab_test.variant_b_html | string | Variant B HTML body. |
ab_test.sample_percent | integer | Percentage of total audience included in the initial A+B test pool (10 to 50, default 20). |
ab_test.winner_criteria | string | Metric used to pick the winning variant: open_rate (unique opens / delivered), click_rate (unique clicks / delivered), or manual (wait until a team member crowns a winner). |
ab_test.test_hours | integer | Hours to wait after the test sample finishes sending before automatically crowning the winner (1 to 168). |
{
"name": "November Black Friday Preview",
"subject": "Early access: 30% off everything inside",
"from_name": "Acme Shop",
"from_email": "news@acme.com",
"reply_to": "support@acme.com",
"html_content": "<h1>Early Access Starts Now</h1><p>Hi {{ contact.FIRSTNAME | default:\"there\" }}, shop first.</p><p><a href=\"{{ unsubscribe }}\">Unsubscribe</a></p>",
"list_ids": [
"7b1a2c3d-d5e6-4f7a-8b9c-0d1e2f3a4b5c"
],
"segment_ids": [
"2a3b4c5d-6e7f-4a8b-9c0d-1e2f3a4b5c6d"
],
"exclude_segment_ids": [],
"ab_test": {
"enabled": true,
"test_type": "subject",
"variant_b_subject": "{{ contact.FIRSTNAME | default:\"Friend\" }}, your private 30% VIP code is ready ๐",
"sample_percent": 20,
"winner_criteria": "open_rate",
"test_hours": 4
}
}Live per-variant progress & report
/api/v1/campaigns/{id}/progressBearer JWT/api/v1/campaigns/{id}/reportBearer JWTBoth the live progress endpoint and the full campaign report return a variants array with real-time metrics broken down by Variant A and Variant B:
{
"status": "SENDING",
"total_recipients": 5000,
"sent_count": 1000,
"delivered_count": 994,
"bounce_count": 6,
"complaint_count": 0,
"open_count": 312,
"click_count": 84,
"delivery_rate": 99.4,
"speed_per_second": 45.2,
"elapsed_seconds": 22,
"ab_test": {
"enabled": true,
"test_type": "subject",
"variant_b_subject": "{{ contact.FIRSTNAME | default:\"Friend\" }}, your private 30% VIP code is ready ๐",
"sample_percent": 20,
"winner_criteria": "open_rate",
"test_hours": 4,
"phase": "WAITING_WINNER",
"test_completed_at": "2026-10-28T15:00:22Z",
"winner_pick_at": "2026-10-28T19:00:22Z"
},
"variants": [
{
"variant": "A",
"sent": 500,
"delivered": 497,
"unique_opens": 134,
"unique_clicks": 36,
"bounces": 3,
"unsubscribes": 1,
"open_rate": 0.2696,
"click_rate": 0.0724
},
{
"variant": "B",
"sent": 500,
"delivered": 497,
"unique_opens": 178,
"unique_clicks": 48,
"bounces": 3,
"unsubscribes": 0,
"open_rate": 0.3581,
"click_rate": 0.0966
}
]
}Manually crown an A/B winner
/api/v1/campaigns/{id}/ab-winnerBearer JWTSelects "A" or "B" as the winner immediately and dispatches the remaining holdout recipients right away.
{
"winner": "B"
}Dynamic audience segments
Segments (/api/v1/segments*) evaluate nested all (AND) / any (OR) rule trees across contact attributes, list memberships and email engagement (opened, clicked, not_opened, never_opened, bounced, unsubscribed). Both email campaigns and WhatsApp broadcast campaigns accept segment_ids and exclude_segment_ids alongside list_ids.
| Method | Path | Description |
|---|---|---|
GET / POST | /api/v1/segments | List saved segments with cached counts or create a new segment. |
POST | /api/v1/segments/preview | Preview matching contact count and sample contacts for unsaved rules. |
POST | /api/v1/segments/audience | Calculate deduplicated net recipient count across list_ids, segment_ids and exclude_segment_ids. |
1-Click Brevo migration API
/api/v1/integrations/brevo/previewBearer JWT/api/v1/integrations/brevo/importBearer JWT/api/v1/integrations/brevo/runsBearer JWTConnects to Brevo's v3 API using a Brevo API key (xkeysib-...) to inspect and import subscriber lists, contacts with all custom attributes, active HTML email templates, and blocklisted/unsubscribed addresses into your SnappyMails brand. Pass "api_key": "demo" to test the importer with built-in sample Brevo data.
{
"api_key": "xkeysib-...",
"import_lists": true,
"import_contacts": true,
"import_templates": true,
"import_suppressions": true
}{
"id": "8d7c6b5a-4e3f-2d1c-9b8a-7f6e5d4c3b2a",
"status": "COMPLETED",
"lists_imported": 3,
"contacts_imported": 1420,
"contacts_updated": 15,
"suppressions_imported": 42,
"templates_imported": 8,
"summary": {
"demo_mode": false
},
"created_at": "2026-10-28T15:20:00Z",
"completed_at": "2026-10-28T15:20:04Z"
}SnapAI writing assistant
Generate responsive email templates, subject lines, preheaders, body copy and WhatsApp templates using /api/v1/snapai/*:
| Method | Path | Description |
|---|---|---|
POST | /api/v1/snapai/email-template | Generate or revise an email-safe 600px HTML template, subject and preheader (supports SSE streaming). |
POST | /api/v1/snapai/subject-lines | Generate high-converting subject line and preheader ideas (great for A/B testing). |
POST | /api/v1/snapai/text | Write, rewrite, shorten, expand, translate or change tone of email copy. |
POST | /api/v1/snapai/whatsapp-template | Generate Meta-compliant WhatsApp templates with variables and buttons. |
Try it in the portal