Admin API Documentation
Admin-level endpoints for system administrators to manage and monitor campaigns, processes, and other administrative functions.
Get Campaign Batches
POST/api/v1/admin.campaign.batchesAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Retrieves a paginated list of batches for a specific campaign with filtering and sorting options. This endpoint provides detailed information about each batch including status, processing statistics, and timing metrics.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaign.batches |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | Campaign ID to retrieve batches for |
| RecordsPerRequest | Integer | No | Number of records per request (default: 50, max: 500). Pass 0 to return all matching records with no row cap. Fixed in v5.9.3 0 is honoured in every request shape — JSON integer 0, JSON string "0", and form-encoded 0. |
| RecordsFrom | Integer | No | Offset for pagination (default: 0) |
| ExactOffset | Boolean | No | New in v5.9.3 When true, RecordsFrom is honoured as an exact row offset. When omitted or false (default), RecordsFrom is floored down to the nearest RecordsPerRequest boundary — the historical behaviour, kept for backward compatibility. |
| Status | String | No | Filter by batch status: Pending, Working, Completed, Failed, Paused |
| OrderField | String | No | Field to sort by: ID, CreatedAt, UpdatedAt, FinishedAt, Status, ProcessedEmails, EmailsPerSec |
| OrderType | String | No | Sort direction: ASC or DESC (default: ASC) |
Pagination offset semantics
By default RecordsFrom is converted to a page number (floor(RecordsFrom / RecordsPerRequest) + 1), so any value that is not an exact multiple of RecordsPerRequest is rounded down to the start of that page. For example, RecordsFrom=25 with RecordsPerRequest=50 returns rows 0–49, not rows 25–74.
Pass ExactOffset: true to have RecordsFrom treated as a true row offset. This is opt-in so that existing integrations keep receiving identical results.
When ExactOffset is enabled together with RecordsPerRequest: 0 ("all records"), the first RecordsFrom rows are skipped and every remaining row is returned.
ExactOffset accepts the usual boolean spellings — true, 1, "1", "true", "yes", "on". Anything else is treated as false and yields the default behaviour. As everywhere on /api.php, the parameter name itself is matched case-insensitively.
curl -X POST https://example.com/api/v1/admin.campaign.batches \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaign.batches",
"APIKey": "your-admin-api-key",
"CampaignID": 123,
"RecordsPerRequest": 50,
"RecordsFrom": 0,
"Status": "Completed",
"OrderField": "FinishedAt",
"OrderType": "DESC"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Batches": [
{
"ID": 123,
"BatchID": "batch_abc123def456",
"Status": "Completed",
"StatusMessage": null,
"CreatedAt": "2025-11-10 14:30:00",
"UpdatedAt": "2025-11-10 14:35:00",
"FinishedAt": "2025-11-10 14:35:00",
"ProcessID": 5,
"WorkerPID": 12345,
"StartedAt": "2025-11-10 14:30:00",
"LastPingedAt": "2025-11-10 14:35:00",
"AttemptCount": 1,
"TotalProcessingTime": 300,
"ProcessedEmails": 1000,
"EmailsPerSec": "3.33",
"CurrentProcessingDuration": 300,
"SecondsSinceLastPing": 120,
"TotalRecipients": 1000,
"PendingRecipients": 0,
"SentRecipients": 995,
"FailedRecipients": 5
}
],
"TotalBatches": 256
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "campaignid parameter is required"
}0: Success
1: campaignid parameter is requiredGet Campaign Details
POST/api/v1/admin.campaign.detailsAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Retrieves comprehensive campaign information including batches, worker assignments, delivery metrics, and health status. This endpoint is designed for campaign monitoring and debugging, providing a complete view of campaign state, performance metrics, and diagnostic information.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaign.details |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | Campaign ID to retrieve details for |
| IncludeBatchDetails | Boolean | No | Include detailed batch information (can be expensive for large campaigns). Default: true |
curl -X POST https://example.com/api/v1/admin.campaign.details \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaign.details",
"APIKey": "your-admin-api-key",
"CampaignID": 123,
"IncludeBatchDetails": true
}'{
"Campaign": {
"CampaignID": 123,
"CampaignName": "Newsletter Campaign",
"CampaignStatus": "Sending",
"TotalRecipients": 25000,
"TotalSent": 9500
},
"QueueTable": {
"Exists": true,
"TableName": "oempro_queue_c_123",
"Stats": {
"TotalRecipients": 25000,
"Pending": 15500,
"Sending": 0,
"Sent": 9500,
"Failed": 0
}
},
"Throughput": {
"EmailsPerSecond": 2.64,
"EmailsPerMinute": 158.4,
"EmailsPerHour": 9504,
"TotalSent": 9500,
"DurationSeconds": 3600,
"EmailsRemaining": 15500,
"EstimatedSecondsRemaining": 5871,
"EstimatedTimeRemaining": "01:37:51"
},
"Velocity": {
"EmailsSentInWindow": 125,
"WindowSeconds": 60,
"ElapsedSeconds": 58,
"EmailsPerSecond": 2.16,
"EmailsRemaining": 15500,
"EstimatedSecondsRemaining": 7176,
"EstimatedTimeRemaining": "01:59:36"
},
"BatchSummary": {
"TotalBatches": 25,
"BatchesByStatus": {
"Pending": 5,
"Working": 10,
"Completed": 8,
"Failed": 2,
"Other": 0
},
"TotalRecipients": 25000,
"TotalAttempts": 28,
"AverageAttemptsPerBatch": 1.12,
"BatchesWithWorkers": 10,
"PotentiallyStuckBatches": 0,
"DiagnosticNote": null
},
"Health": {
"Status": "Healthy",
"Note": "Campaign is actively sending with 5 worker(s) (38.0% complete)",
"Issues": [],
"Warnings": [],
"WorkerTracking": {
"LastWorkerActivityAt": "2025-11-09 14:30:00",
"ActiveWorkerCount": 5,
"SecondsSinceLastActivity": 3,
"IsStuck": false,
"StuckReason": null,
"IsPotentiallyStuck": false,
"HasInactiveWorkers": false
}
}
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "campaignid parameter is required"
}0: Success
1: campaignid parameter is requiredGet Campaign Processes
POST/api/v1/admin.campaign.processesAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Retrieves a paginated list of processes associated with a campaign's batches, along with aggregated counts by hostname. This endpoint is useful for monitoring worker distribution and process health across different servers.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaign.processes |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | Campaign ID to retrieve processes for |
| RecordsPerRequest | Integer | No | Number of records per request (default: 50, max: 500). Pass 0 to return all matching records with no row cap. Fixed in v5.9.3 0 is honoured in every request shape — JSON integer 0, JSON string "0", and form-encoded 0. |
| RecordsFrom | Integer | No | Offset for pagination (default: 0) |
| OrderField | String | No | Field to sort by: ProcessID, PID, Hostname, ProcessType, RegisteredAt, LastPingedAt, MemoryUsage, MemoryPeakUsage (default: LastPingedAt) |
| OrderType | String | No | Sort direction: ASC or DESC (default: DESC) |
curl -X POST https://example.com/api/v1/admin.campaign.processes \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaign.processes",
"APIKey": "your-admin-api-key",
"CampaignID": 123,
"RecordsPerRequest": 50,
"RecordsFrom": 0,
"OrderField": "LastPingedAt",
"OrderType": "DESC"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Processes": [
{
"ProcessID": 123,
"PID": 12345,
"Hostname": "worker-1",
"ProcessType": "campaign_sender",
"RegisteredAt": "2025-11-10 14:30:00",
"LastPingedAt": "2025-11-10 14:35:00",
"MemoryUsage": 52428800,
"MemoryPeakUsage": 67108864,
"KeyMetricValue1": 0,
"KeyMetricValue2": 0,
"KeyMetricValue3": 0,
"KeyMetricValue4": 0,
"KeyMetricValue5": 0
}
],
"TotalProcesses": 10,
"ProcessCountByHostname": [
{
"Hostname": "worker-1",
"ProcessCount": 5
},
{
"Hostname": "worker-2",
"ProcessCount": 3
},
{
"Hostname": "worker-3",
"ProcessCount": 2
}
]
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "campaignid parameter is required"
}0: Success
1: campaignid parameter is requiredGet Campaign Queue
POST/api/v1/admin.campaign.queueAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Retrieves a paginated list of queued emails for a specific campaign with filtering and search options. This endpoint is useful for inspecting individual queue items, debugging email delivery issues, and monitoring queue status.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaign.queue |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | Campaign ID to retrieve queue items for |
| RecordsPerRequest | Integer | No | Number of records per request (default: 50, max: 500). Pass 0 to return all matching records with no row cap. Non-numeric or negative values are invalid and fall back to the default (50). |
| RecordsFrom | Integer | No | Offset for pagination (default: 0) |
| ExactOffset | Boolean | No | New in v5.9.3 When true, RecordsFrom is honoured as an exact row offset. When omitted or false (default), RecordsFrom is floored down to the nearest RecordsPerRequest boundary — the historical behaviour, kept for backward compatibility. |
| Status | String | No | Filter by queue status: Pending, Sending, Sent, Delivered, Failed |
| Search | String | No | Search term for EmailAddress field |
| BatchID | String | No | Filter by specific QueueBatchID |
| IsTest | Boolean | No | Filter by IsTest flag (true/false) |
| OrderField | String | No | Field to sort by: QueueID, EmailAddress, Status, QueuedAt, SentAt, FailedAt, QueueBatchID (default: QueueID) |
| OrderType | String | No | Sort direction: ASC or DESC (default: ASC) |
Pagination offset semantics
By default RecordsFrom is converted to a page number (floor(RecordsFrom / RecordsPerRequest) + 1), so any value that is not an exact multiple of RecordsPerRequest is rounded down to the start of that page. For example, RecordsFrom=25 with RecordsPerRequest=50 returns rows 0–49, not rows 25–74.
Pass ExactOffset: true to have RecordsFrom treated as a true row offset. This is opt-in so that existing integrations keep receiving identical results.
ExactOffset accepts the usual boolean spellings — true, 1, "1", "true", "yes", "on". Anything else is treated as false and yields the default behaviour. As everywhere on /api.php, the parameter name itself is matched case-insensitively.
RecordsPerRequest: 0 returns all records
RecordsPerRequest: 0 returns every matching row with no cap, matching the sibling admin.campaign.batches endpoint. Before v5.9.3 it was silently capped at 500 rows, with nothing in the response indicating that truncation had occurred.A campaign queue can hold millions of rows, and an unbounded request materialises the entire result set — including the Options, SenderSettings and CustomFieldSnapshot payloads — in a single response. For large campaigns, page with an explicit RecordsPerRequest plus ExactOffset, or narrow the result set with Status, BatchID or Search first.
Combining RecordsPerRequest: 0 with ExactOffset: true and a non-zero RecordsFrom returns every remaining row from that offset onward (not just one page). With RecordsFrom: 0, or with ExactOffset omitted, it returns the full result set from the beginning.
Non-numeric (e.g. "abc") or negative values are invalid and fall back to the default page size of 50. Prior to v5.9.3 such values were treated as 0 and returned 500 rows.
RecordsPerRequest: 0 works in every request shape
0 ("RecordsPerRequest": 0), the JSON string "0", and a form-encoded RecordsPerRequest=0 are now all honoured identically as "all records".Before this fix a JSON integer 0 was misread as an omitted parameter and silently replaced with the default page size, so a JSON client following this page verbatim received one page instead of the full result set, with nothing in the response indicating the shortfall. The same fix applies to admin.campaign.batches, admin.campaign.processes and admin.users.activity.
0 = all records is a convention of these admin campaign endpoints, not a global one. It is explicitly not supported on subscribers.get, subscribers.search or journey.action.subscribers — see the note on those commands before passing 0 to them.
curl -X POST https://example.com/api/v1/admin.campaign.queue \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaign.queue",
"APIKey": "your-admin-api-key",
"CampaignID": 123,
"RecordsPerRequest": 50,
"RecordsFrom": 0,
"Status": "Sent",
"Search": "example.com",
"OrderField": "SentAt",
"OrderType": "DESC"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"QueueItems": [
{
"QueueID": 12345,
"RelListID": 10,
"RelSegmentID": 0,
"RelSubscriberID": 5432,
"RelDeliveryServerID": 3,
"RelEmailID": 123,
"IsTest": false,
"EmailAddress": "user@example.com",
"Status": "Sent",
"StatusMessage": "",
"QueueBatchID": "batch_abc123def456",
"Options": null,
"SenderSettings": null,
"QueuedAt": "2025-11-10 14:30:00",
"FailedAt": null,
"SentAt": "2025-11-10 14:35:00",
"CustomFieldSnapshot": null
}
],
"TotalQueueItems": 10000
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "campaignid parameter is required"
}0: Success
1: campaignid parameter is requiredGet Campaign Sending Velocity
POST/api/v1/admin.campaign.sending-velocityAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns time-series data showing how many emails were sent per time interval for a campaign. This endpoint is useful for visualizing sending velocity in charts and graphs, and for monitoring real-time campaign performance. Only available for campaigns in 'Sending' or 'Sent' status.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaign.sending-velocity |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | Campaign ID (must be in 'Sending' or 'Sent' status) |
| Interval | String | No | Time interval for grouping: auto, minute, 5min, 10min, 15min, hour (default: auto). The 'auto' option automatically selects optimal interval to keep data points ≤ 200 |
curl -X POST https://example.com/api/v1/admin.campaign.sending-velocity \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaign.sending-velocity",
"APIKey": "your-admin-api-key",
"CampaignID": 123,
"Interval": "minute"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"CampaignID": 123,
"CampaignStatus": "Sent",
"Interval": "minute",
"DataPoints": [
{
"TimeBucket": "2025-11-10 14:30",
"EmailsSent": 150,
"EmailsPerSecond": 2.5
},
{
"TimeBucket": "2025-11-10 14:31",
"EmailsSent": 145,
"EmailsPerSecond": 2.42
}
],
"Summary": {
"TotalDataPoints": 60,
"TotalEmailsSent": 9000,
"MinEmailsPerInterval": 100,
"MaxEmailsPerInterval": 200,
"AvgEmailsPerInterval": 150,
"FirstSentAt": "2025-11-10 14:30:00",
"LastSentAt": "2025-11-10 15:29:59"
},
"Velocity": {
"EmailsSentInWindow": 125,
"WindowSeconds": 60,
"ElapsedSeconds": 58,
"EmailsPerSecond": 2.16,
"EmailsPerMinute": 129.6,
"EmailsPerHour": 7776,
"EmailsRemaining": 15500,
"EstimatedSecondsRemaining": 7176,
"EstimatedTimeRemaining": "01:59:36"
}
}{
"Success": false,
"ErrorCode": 4,
"ErrorText": "Campaign must be in Sending or Sent status. Current status: Draft"
}0: Success
1: campaignid parameter is required
2: Invalid interval. Valid values: auto, minute, 5min, 10min, 15min, hour
3: Campaign not found
4: Campaign must be in Sending or Sent status
5: Queue table does not exist for this campaignGet Campaigns Overview
POST/api/v1/admin.campaigns.overviewAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Provides campaign status totals and overview counts for admin users. Returns counts for all campaign statuses, currently sending campaigns, sent campaigns (with time filters), and scheduled campaigns (with time filters). This endpoint is useful for dashboard displays and campaign monitoring.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaigns.overview |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
curl -X POST https://example.com/api/v1/admin.campaigns.overview \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaigns.overview",
"APIKey": "your-admin-api-key"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"StatusTotals": {
"Draft": 15,
"Ready": 3,
"Sending": 5,
"Paused": 2,
"PendingApproval": 1,
"Sent": 120,
"Failed": 4,
"Scheduled": 8
},
"CurrentlySending": {
"Count": 5,
"ReadyCount": 3
},
"Sent": {
"Today": 2,
"Past7Days": 15,
"Past30Days": 45
},
"Scheduled": {
"Today": 1,
"Next7Days": 5,
"Next30Days": 8
}
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "Authentication failed"
}0: SuccessSearch Campaigns
POST/api/v1/admin.campaigns.searchAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Searches and filters campaigns across all accounts with admin privileges. This endpoint provides powerful filtering, search, and pagination capabilities, along with optional performance metrics like batch statistics and velocity. By default, statistics are disabled for better performance.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaigns.search |
| 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. Note: 'Scheduled' is mapped to 'Ready' with ScheduleType='Future' |
| SearchKeyword | String | No | Search by campaign name or email subject (LIKE query) |
| FilterByUserID | Integer | No | Filter by account/user ID (empty for all accounts) |
| CampaignIDs | String/Array | No | Filter by specific campaign IDs (comma-separated string or array). Example: "1,2,3" or [1,2,3] |
| DateFrom | String | No | Start date for filtering (Y-m-d format). For Sent campaigns, filters by SendProcessFinishedOn; for Scheduled, filters by SendDate |
| DateTo | String | No | End date for filtering (Y-m-d format) |
| OrderField | String | No | Field to sort by (e.g., CampaignName, SendProcessFinishedOn) |
| OrderType | String | No | Sort direction: ASC or DESC |
| RecordsPerRequest | Integer | No | Number of records per page (0 for all) |
| RecordsFrom | Integer | No | Offset for pagination |
| RetrieveStatistics | Boolean | No | Include campaign statistics (default: false for performance) |
| 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 (e.g., ['Options', 'HTMLContent']) |
| IncludeTotalRecipients | Boolean | No | Include aggregate sums over the filtered window: TotalRecipients, TotalSent, TotalDelivered, TotalFailed, TotalOpens, UniqueOpens, TotalClicks, UniqueClicks, TotalHardBounces, TotalSoftBounces, TotalUnsubscriptions (default: false) |
| IncludeBatchStats | Boolean | No | Include batch statistics for each campaign (default: false) |
| IncludeVelocity | Boolean | No | Include current sending velocity metrics for each campaign (default: false) |
curl -X POST https://example.com/api/v1/admin.campaigns.search \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaigns.search",
"APIKey": "your-admin-api-key",
"CampaignStatus": "Sending",
"SearchKeyword": "newsletter",
"RecordsPerRequest": 25,
"RecordsFrom": 0,
"OrderField": "CreatedOn",
"OrderType": "DESC",
"IncludeBatchStats": true,
"IncludeVelocity": true
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Campaigns": [
{
"CampaignID": 123,
"CampaignName": "Weekly Newsletter",
"CampaignStatus": "Sending",
"RelOwnerUserID": 5,
"UserFirstName": "John",
"UserLastName": "Doe",
"UserEmailAddress": "john@example.com",
"UserCompany": "Example Corp",
"TotalRecipients": 10000,
"TotalSent": 5000,
"TotalFailed": 50,
"CreatedOn": "2025-11-10 14:00:00",
"BatchStats": {
"TotalBatches": 10,
"Pending": 2,
"Working": 3,
"Completed": 5,
"Failed": 0,
"Paused": 0
},
"Velocity": {
"EmailsSentInWindow": 125,
"WindowSeconds": 60,
"ElapsedSeconds": 58,
"EmailsPerSecond": 2.16,
"EmailsPerMinute": 129.6,
"EmailsPerHour": 7776,
"EmailsRemaining": 5000,
"EstimatedSecondsRemaining": 2314,
"EstimatedTimeRemaining": "00:38:34"
}
}
],
"TotalCampaigns": 50,
"AggregateSums": {
"TotalRecipients": 250000,
"TotalSent": 125000,
"TotalDelivered": 121000,
"TotalFailed": 1250,
"TotalOpens": 60000,
"UniqueOpens": 42000,
"TotalClicks": 9800,
"UniqueClicks": 7100,
"TotalHardBounces": 900,
"TotalSoftBounces": 350,
"TotalUnsubscriptions": 640
}
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "Authentication failed"
}0: SuccessGet Email
POST/api.phpAPI Usage Notes
- Authentication required: Admin API Key
- Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Retrieves complete email information for admin users without user restrictions. This allows administrators to view email details from any account, useful for debugging and cross-account support.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.email.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| EmailID | Integer | Yes | Email ID to retrieve |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.email.get",
"APIKey": "your-admin-api-key",
"EmailID": 123
}'{
"Success": true,
"ErrorCode": 0,
"EmailInformation": {
"EmailID": 123,
"EmailName": "Weekly Newsletter Template",
"Subject": "Your Weekly Update",
"HTMLContent": "<html>...</html>",
"TextContent": "Plain text version...",
"RelOwnerUserID": 5,
"CreatedOn": "2025-11-10 14:00:00",
"UpdatedOn": "2025-11-10 15:30:00",
"EmailStatus": "Active"
}
}{
"Success": false,
"ErrorCode": [2]
}0: Success
emailid: Missing required parameter emailid
2: Email not foundSearch Events
POST/api/v1/admin.events.searchAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Searches and filters website tracking events and subscriber activity events across all accounts with admin privileges. This endpoint provides comprehensive filtering by user, list, subscriber, event type, date range, and search keywords. Useful for debugging tracking events, analyzing subscriber activity, and cross-account event monitoring.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.events.search |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| RecordsPerRequest | Integer | No | Number of records per request (default: 0 for all records) |
| RecordsFrom | Integer | No | Offset for pagination (default: 0) |
| FilterByUserID | Integer | No | Filter by account/user ID |
| FilterByListID | Integer | No | Filter by list ID |
| FilterBySubscriberID | Integer | No | Filter by subscriber ID |
| EventType | String | No | Filter by event type (e.g., PageView, EmailOpen, LinkClick, FormSubmit). Use All or omit for all event types |
| SearchKeyword | String | No | Search term for event name (LIKE query) |
| DateFrom | String | No | Start date for filtering (Y-m-d format, e.g., 2025-11-01) |
| DateTo | String | No | End date for filtering (Y-m-d format, e.g., 2025-11-30) |
| WebsiteEventUUID | String | No | Filter by specific website event UUID |
| OrderField | String | No | Field to sort by (e.g., EventID, CreatedAt). Default: EventID. Must be sent together with OrderType — see the sorting note below. |
| OrderType | String | No | Sort direction: ASC or DESC (default: DESC). Must be sent together with OrderField — see the sorting note below. |
| IncludeProperties | Boolean | No | Include event properties/metadata (default: true) |
Sorting parameters are coupled and format-filtered (v5.9.3, #2359)
OrderField and OrderType are validated for shape, not against a list of sortable columns, and they are validated as a pair:
- Both must be present and non-empty. Sending
OrderFieldalone, withoutOrderType, silently yields the default ordering (EventID DESC) — this is the most common surprise here. Always send both. OrderFieldmust be a plain column identifier (letters, digits and underscores, starting with a letter or underscore) andOrderTypemust beASCorDESC. If either fails, the pair is discarded and ordering falls back toEventID DESC.- Because there is no column allow-list, a value that is identifier-shaped but names a column that does not exist is passed through to the query and surfaces as a database error rather than falling back.
The silent-fallback cases return HTTP 200 with Success: true and no error code. If results come back in an unexpected order after upgrading, your sort parameters are being rejected silently — confirm you are sending both of them.
curl -X POST https://example.com/api/v1/admin.events.search \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.events.search",
"APIKey": "your-admin-api-key",
"EventType": "PageView",
"DateFrom": "2025-11-01",
"DateTo": "2025-11-30",
"RecordsPerRequest": 50,
"RecordsFrom": 0,
"OrderField": "CreatedAt",
"OrderType": "DESC",
"IncludeProperties": true
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Events": [
{
"EventID": 12345,
"Event": "PageView",
"UserID": 5,
"ListID": 10,
"SubscriberID": 1234,
"WebsiteEventUUID": "evt_abc123def456",
"CreatedAt": "2025-11-15 14:30:00",
"Properties": {
"page_url": "https://example.com/products",
"page_title": "Product Catalog",
"referrer": "https://google.com",
"user_agent": "Mozilla/5.0..."
}
},
{
"EventID": 12344,
"Event": "FormSubmit",
"UserID": 5,
"ListID": 10,
"SubscriberID": 1234,
"WebsiteEventUUID": "evt_xyz789ghi012",
"CreatedAt": "2025-11-15 14:25:00",
"Properties": {
"form_id": "contact_form",
"form_name": "Contact Us"
}
}
],
"TotalEvents": 1523
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "Authentication failed"
}0: SuccessAdmin Login
POST/api.phpAPI Usage Notes
- No authentication required
- Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Authenticates an administrator and creates a session. This endpoint supports both username/password authentication and Admin API Key authentication. Optional 2FA (Two-Factor Authentication) verification is supported based on system configuration.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.login |
| Username | String | Yes* | Administrator username (*required unless using AdminAPIKey) |
| Password | String | Yes* | Administrator password (*required unless using AdminAPIKey) |
| TFACode | String | Conditional | Two-Factor Authentication code (required if 2FA is enabled for the admin account) |
| AdminAPIKey | String | No | Admin API Key for alternative authentication (bypasses username/password when valid) |
| Disable2FA | Boolean | No | Skip 2FA verification for this request. Honored only when Disable2FAToken is also supplied and valid (see note below). |
| Disable2FAToken | String | Conditional | Server-derived token that authorizes Disable2FA. Required for Disable2FA to take effect. |
Behavior change (v5.9.3, #2317)
Disable2FA alone no longer skips two-factor authentication. In earlier versions any client could send Disable2FA=true and bypass 2FA — a security hole. It is now honored only when accompanied by a matching Disable2FAToken:
Disable2FAToken = HMAC_SHA256("admin.login.disable2fa", SCRTY_SALT) // lowercase hexSCRTY_SALT is a server-side secret from .oempro_env, so only a trusted integration that has access to it can compute the token; an ordinary caller cannot forge it. If SCRTY_SALT is empty the token can never validate and Disable2FA is ignored. When the token is absent or invalid, normal 2FA handling applies — supply TFACode. Authenticating with AdminAPIKey is unaffected.
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.login",
"Username": "admin",
"Password": "securepassword123"
}'curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.login",
"Username": "admin",
"Password": "securepassword123",
"TFACode": "123456"
}'curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.login",
"Username": "admin",
"Password": "any",
"AdminAPIKey": "your-admin-api-key"
}'{
"Success": true,
"ErrorCode": 0,
"SessionID": "abc123def456ghi789",
"AdminInfo": {
"AdminID": 1,
"Username": "admin",
"FirstName": "System",
"LastName": "Administrator",
"EmailAddress": "admin@example.com",
"2FA_Enabled": "No",
"CreatedOn": "2025-01-01 00:00:00",
"LastLoginOn": "2025-11-15 14:30:00"
}
}{
"Success": false,
"ErrorCode": 3
}{
"Success": false,
"ErrorCode": 101
}0: Success
username: Missing required parameter username
password: Missing required parameter password
3: Invalid username or password
101: Invalid 2FA codeAdmin Password Remind
POST/api.phpAPI Usage Notes
- No authentication required
- Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Sends a password reset link to the administrator's email address. This endpoint validates the email address, generates a password reset link, and sends it via email. The reset link contains an MD5 hash of the admin ID for security.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.passwordremind |
| EmailAddress | String | Yes | Administrator email address |
| CustomResetLink | String | No | Custom password reset URL template (base64 encoded). Use %s placeholder for MD5 hash. If not provided, default reset link will be used |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.passwordremind",
"EmailAddress": "admin@example.com"
}'curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.passwordremind",
"EmailAddress": "admin@example.com",
"CustomResetLink": "aHR0cHM6Ly9leGFtcGxlLmNvbS9yZXNldC1wYXNzd29yZD9jb2RlPSVz"
}'{
"Success": true,
"ErrorCode": 0
}{
"Success": false,
"ErrorCode": [2]
}{
"Success": false,
"ErrorCode": [3]
}0: Success
emailaddress: Missing required parameter emailaddress
2: Invalid email address format
3: Email address not found
NOT AVAILABLE IN DEMO MODE.: Feature disabled in demo modeAdmin Password Reset
POST/api.phpAPI Usage Notes
- No authentication required
- Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Resets an administrator's password and sends the new password via email. This endpoint requires the MD5 hash of the admin ID (typically obtained from the password reset link). A new random password is generated, stored in the database, and emailed to the administrator.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.passwordreset |
| AdminID | String | Yes | MD5 hash of the admin ID (obtained from password reset link) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.passwordreset",
"AdminID": "c4ca4238a0b923820dcc509a6f75849b"
}'{
"Success": true,
"ErrorCode": 0
}{
"Success": false,
"ErrorCode": [2]
}0: Success
adminid: Missing required parameter adminid
2: Admin ID not found (invalid reset link)
NOT AVAILABLE IN DEMO MODE.: Feature disabled in demo modeList Processes
POST/api/v1/admin.processes.listAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Retrieves a list of all currently active processes with their details, including process type information, memory usage, key metrics, and health status. This endpoint is useful for monitoring system processes, detecting stale processes, and troubleshooting performance issues.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.processes.list |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| ProcessType | String | No | Filter by process type (e.g., campaign_sender, journey_worker, autoresponder_worker). Use All or omit for all process types |
| PID | Integer | No | Filter by specific process ID (PID) |
| StaleMinutes | Integer | No | Filter processes that haven't pinged in the last X minutes (useful for detecting stale/stuck processes) |
| OrderField | String | No | Field to sort by: ProcessID, PID, ProcessType, RegisteredAt, LastPingedAt, MemoryUsage, MemoryPeakUsage (default: LastPingedAt) |
| OrderType | String | No | Sort direction: ASC or DESC (default: DESC) |
curl -X POST https://example.com/api/v1/admin.processes.list \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.processes.list",
"APIKey": "your-admin-api-key",
"ProcessType": "campaign_sender",
"OrderField": "LastPingedAt",
"OrderType": "DESC"
}'curl -X POST https://example.com/api/v1/admin.processes.list \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.processes.list",
"APIKey": "your-admin-api-key",
"StaleMinutes": 5,
"OrderField": "LastPingedAt",
"OrderType": "ASC"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Processes": [
{
"ProcessID": 123,
"PID": 12345,
"Hostname": "worker-1",
"ProcessType": "campaign_sender",
"ProcessTypeLabel": "Campaign Sender",
"ProcessTypeDescription": "Processes email campaign batches",
"RegisteredAt": "2025-11-10 14:30:00",
"LastPingedAt": "2025-11-10 14:35:00",
"MemoryUsage": 52428800,
"MemoryPeakUsage": 67108864,
"KeyMetricValue1": 1000,
"KeyMetricValue2": 50,
"KeyMetricValue3": 2.5,
"KeyMetricValue4": 0,
"KeyMetricValue5": 0,
"IsHealthy": true,
"SecondsSinceLastPing": 3
}
],
"TotalProcesses": 15,
"AvailableProcessTypes": [
{
"Type": "campaign_sender",
"Label": "Campaign Sender",
"Description": "Processes email campaign batches"
},
{
"Type": "journey_worker",
"Label": "Journey Worker",
"Description": "Processes journey actions and events"
},
{
"Type": "autoresponder_worker",
"Label": "Autoresponder Worker",
"Description": "Processes autoresponder emails"
}
]
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "Authentication failed"
}0: SuccessDelete All Subscribers from a List
POST/api.phpAPI Usage Notes
- Authentication is done by Admin API Key
- Legacy endpoint access via
/api.phpis also supported
Deletes all subscribers from a specific list for a given user account. This endpoint is restricted to administrators and allows deletion across any user account by specifying the UserID. All subscriber records and their tag associations are permanently removed from the specified list. Optionally, the actual tag entities can also be deleted.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.subscribers.delete.all |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| UserID | Integer | Yes | User ID of the account that owns the list |
| ListID | Integer | Yes | List ID to delete all subscribers from |
| DeleteListTags | Boolean | No | If true, deletes the actual tag entities in addition to tag associations (default: false) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.subscribers.delete.all",
"APIKey": "your-admin-api-key",
"UserID": 5,
"ListID": 123,
"DeleteListTags": false
}'{
"Success": true
}{
"Success": false,
"ErrorCode": 4,
"ErrorText": "Access denied to this list"
}0: Success
userid: Missing required parameter userid
listid: Missing required parameter listid
3: Invalid list ID
4: Access denied to this list
5: Failed to delete subscribers
6: Failed to delete tag associations
7: Failed to delete tag entities
8: An error occurred during deletion of all subscribersUpdate Administrator Account
POST/api.phpAPI Usage Notes
- Authentication is done by Admin API Key
- Legacy endpoint access via
/api.phpis also supported
Updates administrator account details including username, email address, name, and optionally password. Administrators can only update their own account information (AdminID must match the logged-in administrator). This endpoint is disabled in demo mode.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.update |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| AdminID | Integer | Yes | Administrator ID to update (must match logged-in admin) |
| Name | String | Yes | Administrator name |
| Username | String | Yes | Administrator username |
| EmailAddress | String | Yes | Administrator email address (must be valid format) |
| Password | String | No | New password (leave empty to keep existing password) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.update",
"APIKey": "your-admin-api-key",
"AdminID": 1,
"Name": "System Administrator",
"Username": "admin",
"EmailAddress": "admin@example.com"
}'curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.update",
"APIKey": "your-admin-api-key",
"AdminID": 1,
"Name": "System Administrator",
"Username": "admin",
"EmailAddress": "admin@example.com",
"Password": "newSecurePassword123"
}'{
"Success": true,
"ErrorCode": 0
}{
"Success": false,
"ErrorCode": 7
}{
"Success": false,
"ErrorCode": 8
}0: Success
adminid: Missing required parameter adminid
name: Missing required parameter name
username: Missing required parameter username
emailaddress: Missing required parameter emailaddress
7: Invalid email address format
8: Admin account is not owned by logged in admin
NOT AVAILABLE IN DEMO MODE.: Feature disabled in demo modeGet User Activity
POST/api.phpAPI Usage Notes
- Authentication is done by Admin API Key
- Legacy endpoint access via
/api.phpis also supported
Retrieves a paginated list of users with their email sending activity status. Users are classified as "Active" or "Idle" based on whether they sent any campaigns or journey emails within the specified activity period. This endpoint provides detailed activity metrics including recent campaign and journey email counts, with support for filtering, searching, and sorting.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.users.activity |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| ActivityPeriod | Integer | No | Number of days to look back for activity (1-365, default: 30) |
| ActivityStatus | String | No | Filter by status: All, Active, Idle (default: All) |
| SearchKeyword | String | No | Search by username, email, first name, last name, or company name |
| RecordsPerRequest | Integer | No | Number of records per request (1-1000, default: 25). Pass 0 for all records. Fixed in v5.9.3 0 is honoured in every request shape — JSON integer 0, JSON string "0", and form-encoded 0. Non-numeric values and booleans now fall back to the default instead of being read as 0. See the caution below before using 0. |
| RecordsFrom | Integer | No | Offset for pagination (default: 0) |
| OrderField | String | No | Field to sort by: Username, CompanyName, LastActivityDateTime, LastSendingActivityDateTime, AccountStatus, UserActivityStatus. Any other value is silently ignored — see the sorting note below. |
| OrderType | String | No | Sort direction: ASC or DESC (default: ASC). Coerced, not validated — any value other than DESC is treated as ASC. |
RecordsPerRequest: 0 removes the row cap entirely
0 does not mean "the maximum of 1000" — it removes the LIMIT from the query, so the response contains every enabled user account matching the filters. On a large installation that is a slow request and a large response body.
Prefer an explicit page size and paginate with RecordsFrom. Use 0 only when you genuinely need the whole set in one call and know the account count is manageable.
Sorting is restricted to an allow-list (v5.9.3, #2321)
OrderField accepts only the six columns listed above. A value outside that list is dropped silently; if no valid column remains, the endpoint falls back to its default ordering (UserActivityStatus DESC, then last activity descending).
OrderType is coerced rather than validated: any value that is not DESC — including a typo or an unrelated string — becomes ASC.
Neither case returns an error. The response is HTTP 200 with Success: true, just ordered differently than requested. If results come back in an unexpected order after upgrading, check your OrderField against the list above.
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.users.activity",
"APIKey": "your-admin-api-key",
"ActivityPeriod": 30,
"ActivityStatus": "Active",
"RecordsPerRequest": 25,
"RecordsFrom": 0,
"OrderField": "LastSendingActivityDateTime",
"OrderType": "DESC"
}'curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.users.activity",
"APIKey": "your-admin-api-key",
"ActivityPeriod": 90,
"ActivityStatus": "Idle",
"SearchKeyword": "example.com"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Users": [
{
"UserID": 5,
"Username": "john.doe",
"EmailAddress": "john@example.com",
"FirstName": "John",
"LastName": "Doe",
"CompanyName": "Example Corp",
"AccountStatus": "Enabled",
"LastActivityDateTime": "2025-11-15 14:30:00",
"UserActivityStatus": "Active",
"RecentCampaignsSent": 3,
"RecentJourneyEmailsSent": 125,
"LastSendingActivityDateTime": "2025-11-15 14:30:00"
},
{
"UserID": 12,
"Username": "jane.smith",
"EmailAddress": "jane@example.com",
"FirstName": "Jane",
"LastName": "Smith",
"CompanyName": "Test Inc",
"AccountStatus": "Enabled",
"LastActivityDateTime": "2025-10-05 10:15:00",
"UserActivityStatus": "Idle",
"RecentCampaignsSent": 0,
"RecentJourneyEmailsSent": 0,
"LastSendingActivityDateTime": null
}
],
"TotalUsers": 45,
"ActivityPeriod": 30,
"ActivityStatus": "Active"
}{
"Success": false,
"ErrorCode": 4,
"ErrorText": "Activity period must be a number between 1 and 365 days"
}0: Success
2: Database query failed
3: Database count query failed
4: Activity period must be a number between 1 and 365 days
5: Activity status must be one of: All, Active, Idle
6: Records per request must be a number between 0 and 1000
7: Records from must be a non-negative numberGet User Activity Summary
POST/api.phpAPI Usage Notes
- Authentication is done by Admin API Key
- Legacy endpoint access via
/api.phpis also supported
Retrieves summary statistics of user activity, showing counts and percentages of Active vs. Idle users. Users are classified based on whether they sent any campaigns or journey emails within the specified activity period. This endpoint is useful for dashboard displays and quick activity overview.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.users.activity.summary |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| ActivityPeriod | Integer | No | Number of days to look back for activity (1-365, default: 30) |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.users.activity.summary",
"APIKey": "your-admin-api-key",
"ActivityPeriod": 30
}'curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.users.activity.summary",
"APIKey": "your-admin-api-key",
"ActivityPeriod": 90
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Summary": [
{
"UserActivityStatus": "Active",
"UserCount": 35,
"Percentage": 70
},
{
"UserActivityStatus": "Idle",
"UserCount": 15,
"Percentage": 30
}
],
"TotalUsers": 50,
"ActivityPeriod": 30
}{
"Success": false,
"ErrorCode": 3,
"ErrorText": "Activity period must be a number between 1 and 365 days"
}0: Success
2: Database query failed
3: Activity period must be a number between 1 and 365 daysUnstuck a Stuck Campaign
POST/api/v1/admin.campaign.unstuckAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Manually unstucks a stuck campaign by resetting stuck batches to Pending status. This endpoint verifies the campaign is actually stuck before resetting batches. A campaign is considered stuck when batches remain in "Working" status with no activity (no ping updates for over 60 seconds) or when batches have a "Working" status but no assigned ProcessID.
The endpoint performs the following operations atomically:
- Validates the campaign exists and is in "Sending" status
- Checks if the campaign is actually stuck using health metrics
- Resets stuck batches to "Pending" status
- Updates campaign's last activity timestamp
- Logs the unstuck action in the stuck campaigns log
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaign.unstuck |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | Campaign ID to unstuck. Must be a campaign in "Sending" status. |
curl -X POST https://example.com/api/v1/admin.campaign.unstuck \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaign.unstuck",
"APIKey": "your-admin-api-key",
"CampaignID": 123
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"BatchesReset": 5,
"Message": "Campaign unstuck successfully. 5 batch(es) reset to Pending status."
}{
"Success": false,
"ErrorCode": 4,
"ErrorText": "Campaign is not stuck. The campaign appears to be processing normally."
}0: Success
1: campaign_id parameter is required
2: Campaign not found
3: Campaign is not in Sending status. Only campaigns in Sending status can be unstuck.
4: Campaign is not stuck. The campaign appears to be processing normally.
5: Database error during unstuck operationMark Campaign as Failed
POST/api/v1/admin.campaign.markfailedAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Marks a stuck campaign as failed by completing all pending/working batches and setting the campaign status to Failed. This endpoint verifies the campaign is actually stuck before marking it as failed. Use this endpoint when a campaign cannot be recovered through the unstuck operation or when you need to definitively end a problematic campaign.
The endpoint performs the following operations atomically:
- Validates the campaign exists and is in "Sending" status
- Checks if the campaign is actually stuck using health metrics
- Marks all pending/working batches as "Completed"
- Updates campaign status to "Failed" with reason
- Sets SendProcessFinishedOn timestamp
- Logs the action in the stuck campaigns log
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.campaign.markfailed |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| CampaignID | Integer | Yes | Campaign ID to mark as failed. Must be a stuck campaign in "Sending" status. |
curl -X POST https://example.com/api/v1/admin.campaign.markfailed \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.campaign.markfailed",
"APIKey": "your-admin-api-key",
"CampaignID": 123
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"BatchesCompleted": 5,
"Message": "Campaign marked as failed successfully. 5 batch(es) completed."
}{
"Success": false,
"ErrorCode": 4,
"ErrorText": "Campaign is not stuck. Only stuck campaigns can be marked as failed."
}0: Success
1: campaign_id parameter is required
2: Campaign not found
3: Campaign is not in Sending status. Only campaigns in Sending status can be marked as failed.
4: Campaign is not stuck. Only stuck campaigns can be marked as failed.
5: Database error during mark as failed operationGet Database Table Statistics
GET/api/v1/admin.database.statsAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Retrieves database table statistics including row counts, data sizes, index sizes, and total sizes for all tables in the current database. Results are ordered by total size (descending). A summary object with aggregate totals is also included.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.database.stats |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
curl -X GET "https://example.com/api/v1/admin.database.stats?APIKey=your-admin-api-key"{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Tables": [
{
"TableName": "oempro_stats_open",
"Engine": "InnoDB",
"TableRows": 7678970,
"DataMB": 597.00,
"IndexMB": 3094.09,
"TotalMB": 3691.09
},
{
"TableName": "oempro_campaigns",
"Engine": "InnoDB",
"TableRows": 1250,
"DataMB": 12.45,
"IndexMB": 3.21,
"TotalMB": 15.66
}
],
"Summary": {
"TotalTables": 85,
"TotalDataMB": 234.56,
"TotalIndexMB": 89.12,
"TotalSizeMB": 323.68
}
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "Database query failed"
}0: Success
1: Database query failedList Stuck Journey Entries
GET/api/v1/admin.journeys.stuckAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns a list of journeys that have stuck entries. An entry is considered "stuck" when a journey worker picked it up (set ActionUpdatedAt) but the worker process was terminated before completing the action, leaving SnoozedUntil as NULL. Stuck entries are identified as those with ActionUpdatedAt older than 5 minutes and SnoozedUntil being NULL.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.journeys.stuck |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
curl -X GET https://example.com/api/v1/admin.journeys.stuck \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.journeys.stuck",
"APIKey": "your-admin-api-key"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"TotalStuckEntries": 15,
"Journeys": [
{
"JourneyID": 42,
"JourneyName": "Welcome Series",
"RelUserID": 1,
"StuckCount": 10
},
{
"JourneyID": 87,
"JourneyName": "Re-engagement Flow",
"RelUserID": 1,
"StuckCount": 5
}
]
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "Database query failed"
}0: Success
1: Database query failedUnstick Stuck Journey Entries
POST/api/v1/admin.journeys.unstuckAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Resets stuck journey entries by setting ActionUpdatedAt to NULL so they get picked up again by the journey worker on its next iteration. Can target all stuck entries or entries for a specific journey.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.journeys.unstuck |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | No | If provided, only unstick entries for this journey. If omitted, unstick all. |
curl -X POST https://example.com/api/v1/admin.journeys.unstuck \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.journeys.unstuck",
"APIKey": "your-admin-api-key",
"JourneyID": 42
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"EntriesReset": 5,
"Message": "5 stuck journey entry(ies) have been reset."
}{
"Success": false,
"ErrorCode": 2,
"ErrorText": "No stuck entries found"
}0: Success
1: Journey not found (when JourneyID is provided but invalid)
2: No stuck entries found
3: Database error during unstuck operationGet Pending Journey Entry Count
GET/api/v1/admin.journeys.pendingAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns the total number of journey entries waiting to be picked up by journey workers, with a per-user breakdown. This helps identify bottlenecks when workers cannot keep up with incoming entries. A "pending" entry matches the same criteria as the worker picking query: the journey must be enabled, the entry must have an action assigned, and the entry must be either fresh (never picked), snoozed and ready, or stuck.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.journeys.pending |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
curl -X GET https://example.com/api/v1/admin.journeys.pending \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.journeys.pending",
"APIKey": "your-admin-api-key"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"TotalPendingEntries": 1523,
"Users": [
{
"UserID": 1,
"Username": "john",
"PendingCount": 1200
},
{
"UserID": 2,
"Username": "jane",
"PendingCount": 323
}
]
}{
"Success": false,
"ErrorCode": 1,
"ErrorText": "Database query failed"
}0: Success
1: Database query failedGet Journey Queue Overview
GET/api/v1/admin.journeys.overviewAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns queue state counts, throughput metrics, and worker health for monitoring journey queue backlogs and processing performance. Useful for dashboards, incident response, and integration with external monitoring tools.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.journeys.overview |
| AdminAPIKey | String | Yes | Admin API key for authentication |
| JourneyID | Integer | No | Filter stats to a specific journey |
curl -X GET "https://example.com/api/v1/admin.journeys.overview?AdminAPIKey=your-admin-api-key&JourneyID=42"{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"QueueStats": {
"TotalActive": 1523,
"NeverTouched": 500,
"WaitingForNextPass": 1023,
"SnoozedCount": 200,
"OverdueCount": 823,
"StuckCount": 15,
"InProgressCount": 485,
"EstimatedDrainMinutes": 45.2
},
"Throughput": {
"PerMinute": 18.2,
"PerSecond": 0.3,
"MeasurementWindowMinutes": 5,
"CompletionsInWindow": 91
},
"Workers": {
"Total": 3,
"Healthy": 2,
"Unhealthy": 1
}
}{
"Success": false,
"ErrorCode": 2,
"ErrorText": "Invalid journey_id parameter"
}0: Success
1: Database query failed
2: Invalid journey_id parameterList Journey Queue Entries
GET/api/v1/admin.journeys.queueAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns a paginated list of journey queue entries with subscriber details, action information, touch state, and due timestamps. Supports filtering by journey, action, and queue status.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.journeys.queue |
| AdminAPIKey | String | Yes | Admin API key for authentication |
| JourneyID | Integer | No | Filter to a specific journey |
| ActionID | Integer | No | Filter to a specific action |
| Status | String | No | Queue status filter. Possible values: all, overdue, snoozed, never_touched, waiting. Default: all |
| SearchKeyword | String | No | Filter by subscriber email address (partial match). LIKE wildcards % and _ in input are treated as literal characters |
| RecordsPerRequest | Integer | No | Page size (default: 25, max: 500) |
| RecordsFrom | Integer | No | Offset for pagination (default: 0) |
| OrderField | String | No | Sort field. Possible values: EntryID, CreatedAt, SnoozedUntil. Default: EntryID |
| OrderType | String | No | Sort direction. Possible values: ASC, DESC. Default: ASC |
curl -X GET "https://example.com/api/v1/admin.journeys.queue?AdminAPIKey=your-admin-api-key&JourneyID=42&Status=overdue&RecordsPerRequest=10&RecordsFrom=0"{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"TotalQueueEntries": 1523,
"QueueEntries": [
{
"EntryID": 101,
"RelUserID": 1,
"RelJourneyID": 42,
"JourneyName": "Welcome Series",
"RelListID": 5,
"RelSubscriberID": 999,
"EmailAddress": "user@example.com",
"RelActionID": 7,
"ActionType": "SendEmail",
"ActionOrderNo": 3,
"TouchState": "NeverTouched",
"DueAt": "2026-04-03 10:00:00",
"CreatedAt": "2026-04-03 09:55:00",
"ActionUpdatedAt": null,
"SnoozedUntil": null
}
]
}{
"Success": false,
"ErrorCode": 2,
"ErrorText": "Invalid status parameter. Allowed values: all, overdue, snoozed, never_touched, waiting"
}0: Success
1: Database query failed
2: Invalid parameter valueGet Subscriber Queue Position
GET/api/v1/admin.journey.queue.positionAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Given a subscriber identifier (entry ID, subscriber ID, or email address), returns the position in the processing queue, estimated time until processing, and current action details. At least one lookup parameter (EntryID, SubscriberID, or Email) must be provided.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.journey.queue.position |
| AdminAPIKey | String | Yes | Admin API key for authentication |
| EntryID | Integer | No | Direct lookup by queue entry ID |
| SubscriberID | Integer | No | Lookup by subscriber ID |
| String | No | Lookup by email address (requires ListID) | |
| ListID | Integer | No | Narrow scope for subscriber or email lookup. Required when using Email |
| JourneyID | Integer | No | Filter to a specific journey |
curl -X GET "https://example.com/api/v1/admin.journey.queue.position?AdminAPIKey=your-admin-api-key&Email=user@example.com&ListID=5"{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Entries": [
{
"EntryID": 101,
"RelJourneyID": 42,
"JourneyName": "Welcome Series",
"RelListID": 5,
"RelSubscriberID": 999,
"EmailAddress": "user@example.com",
"Position": 347,
"EstimatedMinutesUntilProcessed": 19.1,
"TouchState": "NeverTouched",
"DueAt": "2026-04-03 10:00:00",
"CurrentAction": {
"ActionID": 7,
"Action": "SendEmail",
"OrderNo": 3
},
"CreatedAt": "2026-04-03 09:55:00",
"ActionUpdatedAt": null,
"SnoozedUntil": null
}
],
"Throughput": {
"PerMinute": 18.2,
"PerSecond": 0.3
}
}{
"Success": false,
"ErrorCode": 3,
"ErrorText": "list_id is required when searching by email"
}0: Success
1: No lookup parameter provided (must supply EntryID, SubscriberID, or Email)
2: Entry or subscriber not found in queue
3: ListID required when searching by Email
4: Database query failed
5: Invalid parameter valueAudit Journey Action
GET/api/v1/admin.journey.action.auditAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns comprehensive diagnostic data for a specific journey action: action metadata, queue state breakdown, subscription status breakdown, bounce type breakdown, and completion count. Designed for diagnosing stuck entries at a particular action step.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.journey.action.audit |
| AdminAPIKey | String | Yes | Admin API key for authentication |
| ActionID | Integer | Yes | The journey action ID to audit |
curl -X GET "https://example.com/api/v1/admin.journey.action.audit?AdminAPIKey=your-admin-api-key&ActionID=47"{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"ActionMeta": {
"ActionID": 47,
"ActionType": "SendEmail",
"OrderNo": 3,
"JourneyID": 42,
"JourneyName": "Welcome Series",
"JourneyStatus": "Enabled"
},
"QueueState": {
"TotalAtAction": 500,
"NeverTouched": 200,
"WaitingForNextPass": 300,
"OverdueCount": 280,
"SnoozedCount": 15,
"InProgressCount": 5
},
"SubscriptionBreakdown": {
"Subscribed": 420,
"Unsubscribed": 50,
"OptInPending": 10,
"OptOutPending": 5,
"SubscriberNotFound": 15
},
"BounceBreakdown": {
"NotBounced": 400,
"Hard": 60,
"Soft": 25,
"SubscriberNotFound": 15
},
"CompletionCount": 3500
}{
"Success": false,
"ErrorCode": 2,
"ErrorText": "Action not found"
}0: Success
1: Missing or invalid action_id parameter
2: Action not found
3: Database query failedSearch a Subscriber Email Across All Lists
POST/api/v1/admin.subscriber.searchAPI Usage Notes
- Authentication required: Admin API Key
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Given one email address, returns every user/list (across all users) where that address is subscribed — the API analogue of the admin-area "Subscriber Email Search" page (issue #2185). When authenticated as an access-limited subadmin, results are restricted to lists owned by users in the admin's allowed user groups; the global Admin API Key is unrestricted.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: admin.subscriber.search |
| AdminAPIKey | String | Yes | Admin API key for authentication |
| EmailAddress | String | Yes | Exact email address to search for |
curl -X POST https://example.com/api/v1/admin.subscriber.search \
-H "Content-Type: application/json" \
-d '{
"Command": "admin.subscriber.search",
"AdminAPIKey": "your-admin-api-key",
"EmailAddress": "john@example.com"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"EmailAddress": "john@example.com",
"TotalLists": 2,
"Lists": [
{
"ListID": 42,
"ListName": "Newsletter",
"OwnerUserID": 7,
"OwnerName": "Acme Inc",
"SubscriberID": 1234,
"SubscriptionStatus": "Subscribed",
"BounceType": "Not Bounced"
}
]
}{
"Success": false,
"ErrorCode": 2,
"ErrorText": "Invalid EmailAddress parameter"
}0: Success
1: Missing EmailAddress parameter
2: Invalid EmailAddress parameter
Help Portal