Campaign API Documentation
Manage email marketing campaigns through programmatic API access. Create, update, monitor, and control campaign lifecycles.
Cancel a Campaign
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaign.Update - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.cancel |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign to cancel |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.cancel",
"SessionID": "your-session-id",
"CampaignID": 12345
}'{
"Success": true,
"ErrorCode": 0
}{
"Success": false,
"ErrorCode": [1]
}0: Success
1: Missing required parameter (CampaignID)
2: Campaign not found or doesn't belong to userCopy a Campaign
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaign.Create - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.copy |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign to copy |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.copy",
"SessionID": "your-session-id",
"CampaignID": 12345
}'{
"Success": true,
"ErrorCode": 0,
"NewCampaignID": 12346
}{
"Success": false,
"ErrorCode": [1],
"ErrorText": ["Invalid source campaign"]
}0: Success
1: Invalid source campaign or campaign not foundCreate a Campaign
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaign.Create - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.create |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignName | String | Yes | Name of the new campaign |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.create",
"SessionID": "your-session-id",
"CampaignName": "Summer Sale 2025"
}'{
"Success": true,
"ErrorCode": 0,
"CampaignID": 12345
}{
"Success": false,
"ErrorCode": [1]
}0: Success
1: Missing required parameter (CampaignName)Get Campaign Details
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key or Admin API Key
- Required permissions:
Campaign.Get - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign to retrieve |
| RetrieveStatistics | Boolean | No | Include campaign statistics (default: false) |
| StatisticsDays | Integer | No | Time-series window in days for the per-day statistics blocks (Open/Click/etc.), measured from the campaign send start. Default: 15. Clamped to 1–365. |
| RetrieveTags | Boolean | No | Include campaign tags (default: false) |
| SplitABTestStatistics | Boolean | No | Include A/B test statistics (default: false) |
| RetrieveRecipientDomains | Boolean | No | Include recipient domain statistics (default: true) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.get",
"SessionID": "your-session-id",
"CampaignID": 12345,
"RetrieveStatistics": true,
"RetrieveRecipientDomains": true
}'{
"Success": true,
"ErrorCode": 0,
"Campaign": {
"CampaignID": 12345,
"CampaignName": "Summer Sale 2025",
"CampaignStatus": "Sent",
"TotalRecipients": 10000,
"TotalSent": 9950,
"TotalOpens": 3500,
"UniqueOpens": 2100,
"TotalClicks": 850,
"UniqueClicks": 650
},
"CampaignThroughput": {
"EmailsPerSecond": 125.5,
"Duration": 79
}
}{
"Success": false,
"ErrorCode": 2
}0: Success
2: Campaign not found or invalid CampaignIDPause a Campaign
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaign.Update - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.pause |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign to pause |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.pause",
"SessionID": "your-session-id",
"CampaignID": 12345
}'{
"Success": true,
"ErrorCode": 0
}{
"Success": false,
"ErrorCode": 3
}0: Success
1: Missing required parameter (CampaignID)
2: Campaign not found or doesn't belong to user
3: Invalid campaign status (campaign must be Sending or Ready to be paused)Get Campaign Recipients
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key or Admin API Key
- Required permissions:
Campaign.Get - This endpoint only works for unsent campaigns (Draft, Ready, Pending Approval)
- For sent campaigns, use campaign statistics or queue endpoints instead
- Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.recipients.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign |
| OnlyTotal | Boolean | No | Return only total count without recipient details (default: false) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.recipients.get",
"SessionID": "your-session-id",
"CampaignID": 12345,
"OnlyTotal": false
}'{
"Success": true,
"ErrorCode": 0,
"CampaignID": 12345,
"TotalRecipients": 1500,
"Recipients": [
{
"SubscriberID": 101,
"EmailAddress": "user@example.com",
"FirstName": "John",
"LastName": "Doe"
}
]
}{
"Success": false,
"ErrorCode": 4,
"ErrorMessage": "This endpoint only works for unsent campaigns",
"CampaignStatus": "Sent"
}0: Success
1: Missing required parameter (CampaignID)
2: Invalid CampaignID (must be numeric)
3: Campaign not found or access denied
4: Invalid campaign status (must be Draft, Ready, or Pending Approval)
5: Campaign has no RulesJsonBundle or criteria defined
10: Error retrieving campaign recipientsResume a Campaign
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaign.Update - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.resume |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign to resume |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.resume",
"SessionID": "your-session-id",
"CampaignID": 12345
}'{
"Success": true,
"ErrorCode": 0
}{
"Success": false,
"ErrorCode": 3
}0: Success
1: Missing required parameter (CampaignID)
2: Campaign not found or doesn't belong to user
3: Campaign status is not Paused (only Paused campaigns can be resumed)Update a Campaign
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaign.Update - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.update |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign to update |
| CampaignName | String | No | New campaign name |
| CampaignStatus | String | No | Campaign status (Draft, Ready, Sending, Paused, Pending Approval, Sent, Failed) |
| CampaignStatusReason | String | No | Reason for status change |
| RelEmailID | Integer | No | ID of the email content to use |
| ScheduleType | String | No | Schedule type (Not Scheduled, Immediate, Future, Recursive) |
| SendDate | String | No | Send date (YYYY-MM-DD format) - required if ScheduleType=Future. Must be a valid future date (not 0000-00-00) |
| SendTime | String | No | Send time (HH:MM:SS format) - required if ScheduleType=Future. Combined with SendDate and SendTimeZone, the scheduled datetime must be in the future |
| SendTimeZone | String | No | Timezone for scheduled send |
| ScheduleRecDaysOfWeek | String | No | Days of week for recurring campaigns |
| ScheduleRecDaysOfMonth | String | No | Days of month for recurring campaigns |
| ScheduleRecMonths | String | No | Months for recurring campaigns - required if ScheduleType=Recursive |
| ScheduleRecHours | String | No | Hours for recurring campaigns - required if ScheduleType=Recursive |
| ScheduleRecMinutes | String | No | Minutes for recurring campaigns - required if ScheduleType=Recursive |
| ScheduleRecSendMaxInstance | Integer | No | Max instances for recurring campaigns - required if ScheduleType=Recursive |
| ApprovalUserExplanation | String | No | User explanation for approval |
| GoogleAnalyticsDomains | String | No | Google Analytics tracking domains |
| PublishOnRSS | String | No | Publish on RSS (Enabled/Disabled) |
| AutoResendEnabled | Boolean | No | Enable auto-resend to non-openers |
| AutoResendWaitDays | Integer | No | Days to wait before auto-resend - required if AutoResendEnabled=true |
| AutoResendSubject | String | No | Subject line for auto-resend - required if AutoResendEnabled=true |
| AutoResendPreHeaderText | String | No | Pre-header text for auto-resend. If omitted or empty, the auto-resend uses the original campaign's pre-header. |
| OriginalCampaignID | Integer | No | ID of original campaign if this is a resend |
| RecipientListsAndSegments | String | No | Comma-separated list (format: ListID:SegmentID) |
| Exclude_RecipientListsAndSegments | String | No | Comma-separated exclusion list (format: ListID:SegmentID) |
| RulesJsonBundle | String | No | JSON string with advanced recipient selection rules |
| S2SEnabled | Boolean | No | Enable server-to-server tracking |
| ABTesting | Object | No | A/B testing configuration (see A/B Testing Parameters below) |
A/B Testing Parameters:
When the ABTesting object is provided, the campaign is configured as an A/B split test. Each variation references a separate email (created via Email.Create + Email.Update) and is assigned a weight that determines the distribution percentage across recipients.
| Parameter | Type | Required | Description |
|---|---|---|---|
| ABTesting[Variations] | Array | Yes | Array of variation objects (minimum 2, maximum 5) |
| ABTesting[Variations][N][emailid] | Integer | Yes | Email ID for this variation (must belong to the authenticated user) |
| ABTesting[Variations][N][weight] | Integer | Yes | Relative weight for distribution (must be > 0). Distribution percentages are calculated automatically from the weights. For example, two variations with weight 1 each results in 50%/50% distribution. Weights of 1, 1, 2 result in 25%/25%/50% |
Important Notes
- When A/B testing is enabled, the campaign's
RelEmailIDis automatically set to0— do not pass aRelEmailIDalongsideABTesting. - Each variation must have a distribution of at least 1%.
- To disable A/B testing on a campaign, pass an empty
ABTestingparameter. - The system randomly distributes recipients across variations during queue generation, so each subscriber receives exactly one variation.
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.update",
"SessionID": "your-session-id",
"CampaignID": 12345,
"CampaignName": "Updated Summer Sale",
"CampaignStatus": "Ready",
"ScheduleType": "Future",
"SendDate": "2025-06-15",
"SendTime": "10:00:00",
"SendTimeZone": "America/New_York"
}'{
"Success": true,
"ErrorCode": 0
}{
"Success": false,
"ErrorCode": 6
}0: Success
1: Missing required parameter (CampaignID)
2: Campaign not found or doesn't belong to user
3: Invalid campaign status
4: Email not found or doesn't belong to user
5: Invalid schedule type
6: Missing or invalid SendDate for Future schedule (empty, null, or 0000-00-00)
7: Missing SendTime for Future schedule
8: Missing ScheduleRecDaysOfWeek or ScheduleRecDaysOfMonth for Recursive schedule
9: Missing ScheduleRecMonths for Recursive schedule
10: Missing ScheduleRecHours for Recursive schedule
11: Missing ScheduleRecMinutes for Recursive schedule
12: Missing ScheduleRecSendMaxInstance for Recursive schedule
14: Missing or invalid AutoResendWaitDays when AutoResendEnabled=true
15: Missing AutoResendSubject when AutoResendEnabled=true
17: Invalid ABTesting parameter format (must be array)
18: Invalid ABTesting variations format (must be array)
19: Email variation not found or doesn't belong to user
21: Minimum 2 A/B test variations required
22: Maximum 5 A/B test variations allowed
23: Missing required fields in A/B variation (EmailID, Weight)
24: Invalid EmailID or Weight in A/B variation
25: A/B variation distribution percentage below 1%
26: Auto-resend cannot be used with repeating (recursive) campaigns
27: Scheduled send date and time is in the pastGet Campaign Archive URL
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaigns.Get - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaigns.archive.geturl |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| TagID | Integer | Yes | ID of the tag for archive URL |
| TemplateURL | String | No | Custom template URL for archive |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaigns.archive.geturl",
"SessionID": "your-session-id",
"TagID": 5,
"TemplateURL": "https://example.com/archive-template"
}'{
"Success": true,
"ErrorCode": 0,
"URL": "https://example.com/archive/tag/5"
}{
"Success": false,
"ErrorCode": 2
}0: Success
1: Missing required parameter (TagID)
2: Tag not found or doesn't belong to userDelete Campaigns
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaign.Delete - This endpoint also deletes associated auto-resend campaigns automatically
- Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaigns.delete |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| Campaigns | String | Yes | Comma-separated list of campaign IDs to delete |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaigns.delete",
"SessionID": "your-session-id",
"Campaigns": "12345,12346,12347"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": ""
}{
"Success": false,
"ErrorCode": [1]
}0: Success
1: Missing required parameter (Campaigns)Get Campaigns List
POST/api.php (legacy)API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaigns.Get - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaigns.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignStatus | String | No | Filter by status (Draft, Ready, Scheduled, Sending, Sent, Paused, Failed, All) |
| ScheduleType | String/Array | No | Filter by schedule type (Not Scheduled, Immediate, Future, Recursive) |
| SearchKeyword | String | No | Search campaigns by name or email subject (LIKE query) |
| FilterByUserID | Integer | No | Filter by account/user ID (admin only) |
| CampaignIDs | String/Array | No | Filter by specific campaign IDs (comma-separated or array) |
| Date_From | String | No | Start date for filtering (YYYY-MM-DD format) |
| Date_To | String | No | End date for filtering (YYYY-MM-DD format) |
| OrderField | String | No | Field to sort by (CampaignName, SendDate, etc.) |
| OrderType | String | No | Sort direction (ASC or DESC) |
| RecordsPerRequest | Integer | No | Number of records per page (0 for all, default: 0) |
| RecordsFrom | Integer | No | Offset for pagination (default: 0) |
| CountOnly | Boolean | No | Return only TotalCampaigns with an empty Campaigns array (default: false). Skips the full result-set fetch and all per-row enrichment; takes precedence over RecordsPerRequest. Use for cheap count/badge calls. |
| RetrieveStatistics | Boolean | No | Include campaign statistics (default: true) |
| RetrieveTags | Boolean | No | Include campaign tags (default: false) |
| Tags | String | No | Comma-separated tag IDs to filter by |
| SplitABTestStatistics | Boolean | No | Include A/B split test statistics (default: false) |
| ExcludeColumns | Array | No | Column names to exclude from SELECT for performance |
| Include_AutoResend | Boolean | No | Include auto-resend campaigns (default: false) |
| IncludeTotalRecipients | Boolean | No | Include aggregate sums over the filtered window: TotalRecipients, TotalSent, TotalDelivered, TotalFailed, TotalOpens, UniqueOpens, TotalClicks, UniqueClicks, TotalHardBounces, TotalSoftBounces, TotalUnsubscriptions (default: false) |
| RetrieveSetupMeta | Boolean | No | Opt-in draft setup metadata for the Campaigns "Draft" tab readiness checklist (default: false). When absent the response is unchanged. When true, each row in Campaigns[] also carries the extra fields listed below. Adds one bulk email query for the page; the main listing query is unchanged. |
When RetrieveSetupMeta is true, each campaign object additionally includes:
| Field | Type | Description |
|---|---|---|
| EmailSubject | String | Subject of the linked email (via RelEmailID); "" when no email is linked. For an A/B draft (RelEmailID == 0) this is the first variation's subject. |
| HasHTMLContent | Boolean | Whether the linked email (or, for A/B, any variation) has a non-empty HTML body. Presence only — the body itself is never returned. |
| HasPlainContent | Boolean | Whether the linked email (or, for A/B, any variation) has a non-empty plain-text body. Presence only. |
| AudienceListCount | Integer | Number of distinct recipient lists in the audience. Derived from RulesJsonBundle, falling back to the legacy campaign_recipients data for legacy drafts. |
| AudienceSegmentCount | Integer | Number of segments in the audience (criteria with an inline rules filter for modern drafts; rows with a segment ID for legacy drafts). |
| HasAudience | Boolean | Convenience flag: AudienceListCount + AudienceSegmentCount > 0. |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaigns.get",
"SessionID": "your-session-id",
"CampaignStatus": "Sent",
"Date_From": "2025-01-01",
"Date_To": "2025-12-31",
"RecordsPerRequest": 50,
"RecordsFrom": 0,
"OrderField": "SendDate",
"OrderType": "DESC",
"RetrieveStatistics": true
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Campaigns": [
{
"CampaignID": 12345,
"CampaignName": "Summer Sale 2025",
"CampaignStatus": "Sent",
"SendDate": "2025-06-15",
"TotalRecipients": 10000,
"TotalSent": 9950,
"TotalOpens": 3500,
"UniqueOpens": 2100
}
],
"TotalCampaigns": 125
}{
"Success": false,
"ErrorCode": 0
}0: SuccessGet Campaign Status Counts
POST/api.php (legacy)Returns per-status campaign counts in a single GROUP BY query — intended for the Campaign Browse sidebar so it can render all status buckets in one round-trip instead of one campaigns.get call per status. Owner-scoped to the authenticated user.
The response contains two views of the same data: Counts (raw CampaignStatus totals) and Buckets (the sidebar partition, where the single Ready status splits by ScheduleType — Outbox = Sending + Ready/Immediate, Scheduled = Ready/Future|Recursive, Draft = Draft + Ready/Not Scheduled). Counts.Total always equals Buckets.Total.
API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaigns.Get - Legacy endpoint access via
/api.php
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaigns.counts |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| Tags | String | No | CSV of tag IDs to filter by |
| date_from | String | No | Start date (Y-m-d); narrows by SendDate (uniform window across statuses) |
| date_to | String | No | End date (Y-m-d) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaigns.counts",
"APIKey": "your-api-key",
"date_from": "2026-04-01",
"date_to": "2026-04-30"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Counts": {
"Draft": 5,
"Ready": 3,
"Sending": 0,
"Paused": 2,
"Pending Approval": 2,
"Sent": 14,
"Failed": 1,
"Total": 27
},
"Buckets": {
"Sent": 14,
"Outbox": 1,
"Draft": 6,
"Scheduled": 1,
"Paused": 2,
"Pending Approval": 2,
"Failed": 1,
"Total": 27
}
}{
"success": "false",
"errors": { "code": 99999, "message": "Not enough privileges" }
}0: SuccessGet Tags List
POST/api.php (legacy)API Usage Notes
- Authentication required: User API Key
- Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: tags.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "tags.get",
"SessionID": "your-session-id"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"TotalTagCount": 5,
"Tags": [
{
"TagID": 1,
"Tag": "newsletter",
"RelOwnerUserID": 123
},
{
"TagID": 2,
"Tag": "promotion",
"RelOwnerUserID": 123
}
]
}{
"Success": false,
"ErrorCode": 0
}0: SuccessCreate a Tag
POST/api.php (legacy)API Usage Notes
- Authentication required: User API Key
- Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: tag.create |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| Tag | String | Yes | Tag name. Allowed characters: letters, numbers, spaces, hyphens, underscores, percent signs (%). Leading and trailing whitespace is trimmed automatically. |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "tag.create",
"SessionID": "your-session-id",
"Tag": "summer-campaign"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"TagID": 15
}{
"Success": false,
"ErrorCode": 2
}0: Success
1: Missing required parameter (Tag)
2: Tag already exists in the system
3: Invalid tag format (only letters, numbers, spaces, hyphens and underscores allowed, and percent signs)
4: Tag cannot be empty after trimming whitespaceUpdate a Tag
POST/api.php (legacy)API Usage Notes
- Authentication required: User API Key
- Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: tag.update |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| TagID | Integer | Yes | ID of the tag to update |
| Tag | String | Yes | New tag name. Allowed characters: letters, numbers, spaces, hyphens, underscores, percent signs (%). Leading and trailing whitespace is trimmed automatically. |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "tag.update",
"SessionID": "your-session-id",
"TagID": 15,
"Tag": "summer-promotion"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": ""
}{
"Success": false,
"ErrorCode": [1, 2]
}0: Success
1: Missing required parameter (TagID)
2: Missing required parameter (Tag)
3: Invalid tag format (only letters, numbers, spaces, hyphens and underscores allowed, and percent signs)
4: Tag cannot be empty after trimming whitespaceDelete Tags
POST/api.php (legacy)API Usage Notes
- Authentication required: User API Key
- Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: tags.delete |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| Tags | String | Yes | Comma-separated list of tag IDs to delete |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "tags.delete",
"SessionID": "your-session-id",
"Tags": "15,16,17"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": ""
}{
"Success": false,
"ErrorCode": [1]
}0: Success
1: Missing required parameter (Tags)Assign Tag to Campaigns
POST/api.php (legacy)API Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaigns.Get - Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: tag.assigntocampaigns |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| TagID | Integer | Yes | ID of the tag to assign |
| CampaignIDs | String | Yes | Comma-separated list of campaign IDs |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "tag.assigntocampaigns",
"SessionID": "your-session-id",
"TagID": 15,
"CampaignIDs": "100,101,102"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": ""
}{
"Success": false,
"ErrorCode": [1, 2]
}0: Success
1: Missing required parameter (TagID)
2: Missing required parameter (CampaignIDs)Unassign Tag from Campaigns
POST/api.php (legacy)API Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaigns.Get - Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: tag.unassignfromcampaigns |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| TagID | Integer | Yes | ID of the tag to unassign |
| CampaignIDs | String | Yes | Comma-separated list of campaign IDs |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "tag.unassignfromcampaigns",
"SessionID": "your-session-id",
"TagID": 15,
"CampaignIDs": "100,101,102"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": ""
}{
"Success": false,
"ErrorCode": [1, 2]
}0: Success
1: Missing required parameter (TagID)
2: Missing required parameter (CampaignIDs)Create an A/B Split Test Campaign
A/B split test campaigns allow you to send different email variations to segments of your audience and compare performance. The system randomly distributes recipients across variations based on configurable weights.
How A/B Split Testing Works
- Create a campaign using
Campaign.Create - Create email variations — one
Email.Create+Email.Updatecall per variation (minimum 2, maximum 5) - Configure the campaign using
Campaign.UpdatewithABTesting[Variations], audience rules, and schedule - The system handles the rest — during delivery, recipients are randomly assigned to variations based on distribution weights
When the campaign is sent, each recipient receives exactly one email variation. Statistics (opens, clicks, conversions, unsubscriptions, revenue) are tracked per variation, allowing you to compare performance.
Step-by-Step Example
# Create the campaign shell
curl -X POST https://example.com/api.php \
-d 'ResponseFormat=JSON' \
-d 'Command=Campaign.Create' \
-d 'APIKey=your-api-key' \
-d 'CampaignName=A/B Test: Subject Line Comparison'
# Response: {"Success": true, "ErrorCode": 0, "CampaignID": 200}# --- Variation A ---
# Create the first email
curl -X POST https://example.com/api.php \
-d 'ResponseFormat=JSON' \
-d 'Command=Email.Create' \
-d 'APIKey=your-api-key'
# Response: {"Success": true, "ErrorCode": 0, "EmailID": 301}
# Set the content for Variation A
curl -X POST https://example.com/api.php \
-d 'ResponseFormat=JSON' \
-d 'Command=Email.Update' \
-d 'APIKey=your-api-key' \
-d 'EmailID=301' \
-d 'ValidateScope=Campaign' \
-d 'EmailName=Variation A - Discount Subject' \
-d 'Subject=Save 50% Today Only!' \
-d 'FromName=My Store' \
-d 'FromEmail=deals@mystore.com' \
-d 'ReplyToName=My Store' \
-d 'ReplyToEmail=deals@mystore.com' \
-d 'Mode=Editor' \
-d 'HTMLContent=<html><body><h1>Half Price Sale!</h1><p>...</p><p><a href="%Link:Unsubscribe%">Unsubscribe</a></p></body></html>'
# --- Variation B ---
# Create the second email
curl -X POST https://example.com/api.php \
-d 'ResponseFormat=JSON' \
-d 'Command=Email.Create' \
-d 'APIKey=your-api-key'
# Response: {"Success": true, "ErrorCode": 0, "EmailID": 302}
# Set the content for Variation B
curl -X POST https://example.com/api.php \
-d 'ResponseFormat=JSON' \
-d 'Command=Email.Update' \
-d 'APIKey=your-api-key' \
-d 'EmailID=302' \
-d 'ValidateScope=Campaign' \
-d 'EmailName=Variation B - Urgency Subject' \
-d 'Subject=Last Chance: Sale Ends at Midnight' \
-d 'FromName=My Store' \
-d 'FromEmail=deals@mystore.com' \
-d 'ReplyToName=My Store' \
-d 'ReplyToEmail=deals@mystore.com' \
-d 'Mode=Editor' \
-d 'HTMLContent=<html><body><h1>Sale Ending Soon!</h1><p>...</p><p><a href="%Link:Unsubscribe%">Unsubscribe</a></p></body></html>'# Update the campaign with A/B testing, audience, and schedule
curl -X POST https://example.com/api.php \
-d 'ResponseFormat=JSON' \
-d 'Command=Campaign.Update' \
-d 'APIKey=your-api-key' \
-d 'CampaignID=200' \
-d 'CampaignStatus=Ready' \
-d 'ScheduleType=Immediate' \
-d 'RulesJsonBundle={"operator":"and","criteria":[{"list_id":1,"operator":"and","rules":[[{"type":"fields","field_id":"EmailAddress","operator":"is_not_empty","value":""}]]}]}' \
-d 'ABTesting[Variations][0][emailid]=301' \
-d 'ABTesting[Variations][0][weight]=1' \
-d 'ABTesting[Variations][1][emailid]=302' \
-d 'ABTesting[Variations][1][weight]=1'
# Response: {"Success": true, "ErrorCode": 0}
# With equal weights of 1, each variation receives ~50% of recipients.# Retrieve campaign with A/B test statistics
curl -X POST https://example.com/api.php \
-d 'ResponseFormat=JSON' \
-d 'Command=Campaign.Get' \
-d 'APIKey=your-api-key' \
-d 'CampaignID=200' \
-d 'RetrieveStatistics=true' \
-d 'SplitABTestStatistics=true'
# The response includes per-variation stats inside Campaign.Options.ABTesting.Variations:
# Each variation object includes: EmailID, Weight, Distribution,
# TotalRecipient, TotalSent, TotalFailed, UniqueOpens, UniqueClicks,
# TotalRevenue, TotalUnsubscriptionsUnequal Weight Distribution
You can assign different weights to send more traffic to a preferred variation:
# 75% to Variation A, 25% to Variation B
-d 'ABTesting[Variations][0][emailid]=301'
-d 'ABTesting[Variations][0][weight]=3'
-d 'ABTesting[Variations][1][emailid]=302'
-d 'ABTesting[Variations][1][weight]=1'
# Three variations: 50% / 25% / 25%
-d 'ABTesting[Variations][0][emailid]=301'
-d 'ABTesting[Variations][0][weight]=2'
-d 'ABTesting[Variations][1][emailid]=302'
-d 'ABTesting[Variations][1][weight]=1'
-d 'ABTesting[Variations][2][emailid]=303'
-d 'ABTesting[Variations][2][weight]=1'Retrieving A/B Test Statistics
When retrieving a campaign with SplitABTestStatistics=true, the response includes per-variation performance metrics:
{
"Success": true,
"Campaign": {
"CampaignID": 200,
"CampaignName": "A/B Test: Subject Line Comparison",
"CampaignStatus": "Sent",
"RelEmailID": 0,
"Options": {
"ABTesting": {
"Variations": [
{
"EmailID": 301,
"Weight": 1,
"Distribution": 50,
"TotalRecipient": 5000,
"TotalSent": 4980,
"TotalFailed": 20,
"UniqueOpens": 1200,
"UniqueClicks": 350,
"TotalRevenue": 15000,
"TotalUnsubscriptions": 5
},
{
"EmailID": 302,
"Weight": 1,
"Distribution": 50,
"TotalRecipient": 5000,
"TotalSent": 4975,
"TotalFailed": 25,
"UniqueOpens": 1450,
"UniqueClicks": 420,
"TotalRevenue": 18500,
"TotalUnsubscriptions": 3
}
]
}
},
"OpenStatistics": { ... },
"ClickStatistics": { ... }
}
}When SplitABTestStatistics=true, the OpenStatistics, ClickStatistics, ConversionStatistics, and UnsubscriptionStatistics objects also include per-variation breakdowns grouped by RelEmailID.
Disabling A/B Testing
To remove A/B testing from a campaign and revert to a single email, pass an empty ABTesting parameter and set RelEmailID:
curl -X POST https://example.com/api.php \
-d 'ResponseFormat=JSON' \
-d 'Command=Campaign.Update' \
-d 'APIKey=your-api-key' \
-d 'CampaignID=200' \
-d 'ABTesting=' \
-d 'RelEmailID=301'Copying an A/B Test Campaign
Use Campaign.Copy to duplicate an A/B test campaign. All email variations are automatically duplicated with new Email IDs, and the A/B testing configuration is preserved in the copy.
Create a Split Test (Legacy)
Legacy API
This endpoint uses the older split test system where a test portion of recipients receive different email variations, the campaign pauses to wait for results, then the winning variation is sent to the remaining audience. For the modern A/B testing approach where all recipients are distributed across variations simultaneously, see Create an A/B Split Test Campaign above.
/api.php (legacy)API Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: splittest.create |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign to create split test for |
| TestSize | Integer | Yes | Percentage of recipients to include in test (e.g., 20 for 20%) |
| TestDuration | Integer | Yes | Duration in seconds to wait before selecting the winner |
| Winner | String | Yes | Winner criteria: Highest Open Rate or Most Unique Clicks |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "splittest.create",
"SessionID": "your-session-id",
"CampaignID": 12345,
"TestSize": 20,
"TestDuration": 86400,
"Winner": "Highest Open Rate"
}'{
"Success": true,
"ErrorCode": 0,
"SplitTestID": 567
}{
"Success": false,
"ErrorCode": [1, 2]
}0: Success
1: Missing required parameter (CampaignID)
2: Missing required parameter (TestSize)
4: Missing required parameter (TestDuration)
5: Missing required parameter (Winner)
6: Campaign not found or doesn't belong to userRetry Failed Recipients
POST/api/v1/admin.campaign.retryfailedAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Retries failed recipients for campaigns with status "Sent" or "Failed". This endpoint resets failed queue entries to Pending, creates new delivery batches, sets the campaign to "Sending" status, and pushes it to RabbitMQ for delivery workers to process.
Important: This endpoint bypasses the campaign picker and handles batch creation + RabbitMQ publishing directly. This ensures only the original failed recipients are retried without re-inserting subscribers who joined target lists after the original send.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaign.retryfailed |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | ID of the campaign to retry failed recipients for |
curl -X POST https://example.com/api/v1/admin.campaign.retryfailed \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaign.retryfailed",
"APIKey": "your-admin-api-key",
"CampaignID": 4069
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"RetriedCount": 150,
"BatchesCreated": 1,
"Message": "150 failed recipients queued for retry in 1 batch(es)."
}{
"Success": false,
"ErrorCode": 3,
"ErrorText": "Campaign is not in Sent or Failed status. Only completed or failed campaigns can have their failed recipients retried."
}0: Success
1: campaign_id parameter is required
2: Campaign not found
3: Campaign is not in Sent or Failed status
4: Queue table does not exist for this campaign
5: No failed recipients found for this campaign
6: Database error during retry operationExport Campaigns to CSV
POST/api/v1/campaigns.exportEnqueues a background job that exports the campaigns list (past sends plus engagement aggregates) to a CSV file. Accepts the same filter shape as Get Campaigns List, so the export matches the equivalent campaigns.get query row-for-row (subject to the selected column allow-list). Returns a JobID to poll with Get Campaign Export Status.
API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaigns.Get - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaigns.export.post |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| ExportFormat | String | No | Output format. Possible values: csv. (json is reserved for a future release and currently rejected.) Defaults to csv. |
| FieldsToExport | Array | No | Columns to include, from the allow-list (see below). Defaults to a standard column set when omitted. |
| CampaignStatus | String | No | Filter by status (Draft, Ready, Scheduled, Sending, Sent, Paused, Failed, All) |
| ScheduleType | String/Array | No | Filter by schedule type (Not Scheduled, Immediate, Future, Recursive) |
| SearchKeyword | String | No | Search campaigns by name or email subject (LIKE query) |
| CampaignIDs | String/Array | No | Filter by specific campaign IDs (comma-separated or array) |
| Tags | String | No | Comma-separated tag IDs to filter by |
| Date_From | String | No | Start date for filtering (YYYY-MM-DD format) |
| Date_To | String | No | End date for filtering (YYYY-MM-DD format) |
| FilterByUserID | Integer | No | Filter by account/user ID (admin only) |
| Include_AutoResend | Boolean | No | Include auto-resend campaigns (default: false) |
| SplitABTestStatistics | Boolean | No | Emit one row per A/B variation under each parent campaign (default: false) |
Allowed FieldsToExport values: CampaignID, CampaignName, EmailSubject, CampaignStatus, ScheduleType, SendDate, SendTime, CreateDateTime, SendProcessStartedOn, SendProcessFinishedOn, TotalRecipients, TotalSent, TotalFailed, TotalDelivered, TotalOpens, UniqueOpens, TotalClicks, UniqueClicks, TotalConversions, UniqueConversions, TotalForwards, UniqueForwards, TotalViewsOnBrowser, UniqueViewsOnBrowser, TotalUnsubscriptions, TotalHardBounces, TotalSoftBounces, TotalRevenue, RecipientLists, RecipientSegments.
curl -X POST https://example.com/api/v1/campaigns.export \
-H "Content-Type: application/json" \
-d '{
"Command": "campaigns.export.post",
"SessionID": "your-session-id",
"CampaignStatus": "Sent",
"Tags": "5,12",
"Date_From": "2026-04-01",
"Date_To": "2026-04-30",
"ExportFormat": "csv",
"FieldsToExport": ["CampaignID", "CampaignName", "EmailSubject", "SendProcessFinishedOn", "TotalRecipients", "TotalSent", "TotalDelivered", "UniqueOpens", "UniqueClicks", "TotalHardBounces", "TotalSoftBounces", "TotalUnsubscriptions"],
"SplitABTestStatistics": false,
"Include_AutoResend": true
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"JobID": 8421,
"ExportID": 8421,
"EstimatedRows": 173
}{
"Errors": [
{ "Code": 1, "Message": "Invalid ExportFormat (only \"csv\" is currently supported)" }
]
}0: Success
1: Invalid ExportFormat (only "csv" is currently supported)
2: FieldsToExport must be a non-empty array
3: FieldsToExport contains unknown field(s)Get Campaign Export Status
GET/api/v1/campaigns.exportPolls the status of a campaign export job created by Export Campaigns to CSV, or streams the produced file. When Download=1 and the job is finished, the endpoint streams the CSV directly with explicit Content-Type: text/csv and Content-Disposition: attachment headers (it does not return JSON in that case).
API Usage Notes
- Authentication is done by User API Key
- Required permissions:
Campaigns.Get - Rate limit: 100 requests per 60 seconds
- A job can only be accessed by its owner, and only as a
CampaignExportjob (aSubscriberExport/JourneyExportID owned by the same user returns "not found") - Legacy endpoint access via
/api.phpis also supported
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaigns.export.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JobID | Integer | Yes | The export job ID returned by campaigns.export.post (alias: ExportID) |
| Download | Boolean | No | When 1 and Status=Finished, streams the CSV file instead of returning the JSON envelope |
# Poll status
curl -X GET "https://example.com/api/v1/campaigns.export?Command=campaigns.export.get&SessionID=your-session-id&JobID=8421"
# Download the finished file
curl -X GET "https://example.com/api/v1/campaigns.export?Command=campaigns.export.get&SessionID=your-session-id&JobID=8421&Download=1" -o campaigns.csv{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"JobID": 8421,
"Status": "Finished",
"Progress": 100,
"RowCount": 173,
"DownloadURL": "api.php?Command=campaigns.export.get&jobid=8421&download=1",
"DownloadSize": 28456,
"ExpiresAt": "2026-05-07 15:37:58"
}{
"Errors": [
{ "Code": 5, "Message": "Export job is not completed yet" }
]
}0: Success
1: Missing JobID parameter
2: Invalid JobID parameter (not a positive integer)
3: Export job not found (wrong owner or never existed)
4: Export job not found (job exists but is not a CampaignExport)
5: Download requested but the job is not finished yetGet Campaign Link Clicks
POST/api.phpAPI Usage Notes
- Authentication required: User API Key (or Admin API Key)
- Required permissions:
Campaign.Get - Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Returns the per-link click ranking ("most clicked links") of a sent campaign, or the per-subscriber click breakdown ("who clicked"), depending on GroupBy. Results are ordered by click count (descending) and paginated. Automated/bot clicks are excluded (IsAutomated=0), so the numbers match the bundled campaign report. Access is owner-scoped; admins (via Admin API Key) may read any campaign.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.linkclicks.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | The campaign to report on |
| GroupBy | String | No | Grouping mode. Possible values: Links (default), Subscribers |
| RecordsFrom | Integer | No | Pagination offset (default: 0) |
| RecordsPerRequest | Integer | No | Page size (default: 25, hard cap: 1000) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.linkclicks.get",
"APIKey": "your-api-key",
"CampaignID": 7524,
"GroupBy": "Links",
"RecordsPerRequest": 25
}'{
"Success": true,
"ErrorCode": 0,
"CampaignID": 7524,
"GroupBy": "Links",
"TotalRecords": 12,
"Links": [
{
"LinkTitle": "Read more",
"LinkURL": "https://example.com/landing",
"TotalClicks": 2771
}
]
}{
"Success": false,
"ErrorCode": 3,
"ErrorMessage": "Campaign not found or access denied"
}0: Success
2: CampaignID is not numeric
3: Campaign not found or access deniedWhen GroupBy is Subscribers, the response returns a Subscribers array instead of Links, where each row is { "SubscriberID": 62362, "ListID": 47, "EmailAddress": "user@example.com", "TotalClicks": 3 }. Seed-list recipients (SubscriberID 0) are returned with an empty EmailAddress.
Get Campaign Recipients Activity
POST/api.phpAPI Usage Notes
- Authentication required: User API Key (or Admin API Key)
- Required permissions:
Campaign.Get - Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
For a sent campaign, returns the per-subscriber engagement breakdown for a single activity type ("who opened", "who clicked", "who bounced", etc.), read from the MySQL oempro_stats_* tables. Results are grouped per subscriber (one row per subscriber/list), ordered by most recent activity, and paginated. This is the sent-campaign counterpart to campaign.recipients.get, which only previews the audience of unsent campaigns. Automated/bot opens and clicks are excluded (IsAutomated=0). Access is owner-scoped.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.recipients.activity.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | The campaign to report on |
| Activity | String | Yes | Activity type. Possible values: open, click, bounce, unsubscription, forward, conversion |
| SearchKeyword | String | No | Case-insensitive substring filter on the recipient's email address (LIKE %keyword%), applied before pagination so TotalRecords reflects the filtered count. Empty/absent = no filter. EmailAddress is accepted as an alias. |
| RecordsFrom | Integer | No | Pagination offset (default: 0) |
| RecordsPerRequest | Integer | No | Page size (default: 25, hard cap: 1000) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.recipients.activity.get",
"APIKey": "your-api-key",
"CampaignID": 7524,
"Activity": "click",
"RecordsPerRequest": 25
}'{
"Success": true,
"ErrorCode": 0,
"CampaignID": 7524,
"Activity": "click",
"TotalRecords": 1488,
"Recipients": [
{
"SubscriberID": 62362,
"ListID": 47,
"ListName": "Buyers List",
"EmailAddress": "user@example.com",
"ActivityCount": 2,
"LastActivityDate": "2026-05-28 00:33:36"
}
]
}{
"Success": false,
"ErrorCode": 4,
"ErrorMessage": "Invalid activity. Allowed: open, click, bounce, unsubscription, forward, conversion"
}0: Success
2: CampaignID is not numeric
3: Campaign not found or access denied
4: Invalid activity typeFor bounce, each recipient row additionally includes a BounceType field (Hard or Soft). For conversion, each row additionally includes TotalRevenue (decimal string; stored internally as integer cents).
Each row carries ListName (the subscriber's list name) alongside ListID. When SearchKeyword (or its EmailAddress alias) is supplied, the email match is performed server-side across every list the campaign targeted, before pagination — so TotalRecords is the filtered total and RecordsFrom/RecordsPerRequest page through the matches. Seed-list recipients (SubscriberID 0) have no email address and are therefore excluded from search results.
Get Campaign A/B Test & Auto-Resend Uplift
POST/api.phpAPI Usage Notes
- Authentication required: User API Key (or Admin API Key)
- Required permissions:
Campaign.Get - Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Exposes the per-variation A/B (MVT) statistics and the auto-resend uplift metrics that the bundled campaign report assembles. Per-variation metrics exclude seed-list recipients so the numbers reflect the weighted audience split. The response always contains ABTest, AutoResend, and ParentCampaign keys; AutoResend and ParentCampaign are null when not applicable, and ABTest.IsABTest is false for non-A/B campaigns. Access is owner-scoped.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: campaign.abtest.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | The campaign to report on |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "campaign.abtest.get",
"APIKey": "your-api-key",
"CampaignID": 7524
}'{
"Success": true,
"ErrorCode": 0,
"CampaignID": 7524,
"ABTest": {
"IsABTest": true,
"Variations": [
{
"EmailID": 9001,
"EmailName": "Variation A",
"Subject": "Subject A",
"FromName": "Acme",
"FromEmail": "news@acme.com",
"ContentType": "HTML",
"TotalRecipients": 5000,
"TotalSent": 4980,
"TotalFailed": 20,
"UniqueOpens": 1200,
"UniqueClicks": 300,
"Unsubscriptions": 5,
"Revenue": "120.00",
"OpenRate": 24.1,
"ClickRate": 6,
"CTOR": 25
}
],
"Winner": {
"EmailID": 9001,
"EmailName": "Variation A"
}
},
"AutoResend": {
"Status": "completed",
"CampaignID": 7600,
"CampaignName": "Resend to non-openers",
"TotalSent": 3000,
"UniqueOpens": 400,
"UniqueClicks": 90,
"OpenRate": 13.3,
"ClickRate": 3,
"OpenUplift": 33.3,
"ClickUplift": 30
},
"ParentCampaign": null
}{
"Success": false,
"ErrorCode": 3,
"ErrorMessage": "Campaign not found or access denied"
}0: Success
2: CampaignID is not numeric
3: Campaign not found or access deniedAutoResend.Status is completed when the auto-resend child campaign has been created (uplift fields are populated relative to this parent), or scheduled when auto-resend is enabled but not yet sent (in which case it carries WaitDays, Subject, and PreHeaderText). When the requested campaign is itself an auto-resend child, ParentCampaign is populated with the parent's headline metrics and CTOR.

Help Portal