Journey API Documentation
Journey management endpoints for creating, updating, and managing customer journeys. Journeys allow you to automate subscriber interactions based on triggers and actions.
Create a Journey
POST/api/v1/journeyAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.create |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| Name | String | Yes | Name of the journey |
| Trigger | String | No | Journey trigger type (default: Manual). Possible values: Manual, ListSubscription, ListUnsubscription, EmailOpen, EmailConversion, EmailLinkClick, Tag, UnTag, CustomFieldValueChanged, RevenueHit, JourneyCompleted, ScheduledPull, WebsiteEvent_pageView, WebsiteEvent_identify, WebsiteEvent_customEvent, WebsiteEvent_conversion. See Scheduled Pull Trigger for its additional parameters. |
| TriggerParameters | Object | No | Trigger-specific settings. Required for the ScheduledPull trigger (interval, subscriber count, time window, frequency cap). See Scheduled Pull Trigger. |
| Trigger_ListID | Integer | No | List ID for list-based triggers |
| Trigger_EmailID | Integer | No | Email ID for email-based triggers |
| Trigger_Value | String/Integer | No | Trigger value for specific triggers |
| Trigger_Criteria | Array | No | Criteria for trigger conditions |
| Run_Criteria | Array | No | Run criteria for journey execution |
| Run_Criteria_Operator | String | No | Operator for run criteria. Possible values: and, or (default: and) |
| Rate_Limit_Per_Hour | Integer | No | Hourly rate limit for journey triggers |
| Rate_Limit_Per_Day | Integer | No | Daily rate limit for journey triggers |
| Notes | String | No | Journey notes |
curl -X POST https://example.com/api/v1/journey \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.create",
"SessionID": "your-session-id",
"Name": "Welcome Series",
"Trigger": "ListSubscription",
"Trigger_ListID": 123,
"Notes": "Onboarding journey for new subscribers"
}'{
"JourneyID": 456,
"Journey": {
"JourneyID": "456",
"JourneyName": "Welcome Series",
"Trigger": "ListSubscription",
"Status": "Disabled",
"Notes": "Onboarding journey for new subscribers",
"CreatedAt": "2025-01-15 10:30:00",
"UpdatedAt": "2025-01-15 10:30:00"
}
}{
"Errors": [
{
"Code": 1,
"Message": "Missing Name parameter"
}
]
}0: Success
1: Missing Name parameter
3: Invalid trigger
4: Missing Trigger_ListID parameter
5: Invalid Trigger_ListID parameter
6: Trigger_ListID matching record not found
7: Missing Trigger_EmailID parameter
8: Invalid Trigger_EmailID parameter
9: Trigger_EmailID matching record not found
10: Invalid Trigger_Value parameter
11: Trigger_Value matching record not found
12: Invalid Trigger_Value parameter (CustomFieldValueChanged)
13: Trigger_Value matching record not found (CustomFieldValueChanged)
14: Invalid Trigger_Value parameter (RevenueHit)
15: Missing Trigger_Value parameter (RevenueHit)
16: Invalid Trigger_Value parameter (JourneyCompleted)
17: Trigger_Value matching record not found (JourneyCompleted)
18: Invalid rate_limit_per_hour parameter
19: Invalid rate_limit_per_day parameter
20: Missing or invalid Trigger_ListID parameter for ScheduledPull trigger
21: Trigger_ListID matching record not found (ScheduledPull)Scheduled Pull Trigger
Unlike event-based triggers (which fire when a subscriber does something), the ScheduledPull trigger periodically pulls a batch of random subscribers from a list and enrolls them into the journey on a recurring schedule. It is useful for list warm-up, drip re-engagement, and steady-rate enrollment.
When Trigger is set to ScheduledPull:
Trigger_ListIDis required — it is the list subscribers are pulled from (must be a positive list ID owned by the user).- All scheduling behavior is supplied via the
TriggerParametersobject. Any keys you omit fall back to the defaults below.
TriggerParameters keys:
| Key | Type | Default | Description |
|---|---|---|---|
| IntervalValue | Integer | 60 | How often the pull runs, combined with IntervalUnit. |
| IntervalUnit | String | minutes | Unit for IntervalValue. Values: minutes, hours, days. The effective interval is floored at 60 seconds. |
| SubscriberCountMode | String | fixed | How many subscribers to pull per run. Values: fixed, random. |
| SubscriberCountFixed | Integer | 10 | Number of subscribers pulled per run when SubscriberCountMode is fixed. |
| SubscriberCountMin | Integer | 1 | Lower bound when SubscriberCountMode is random. |
| SubscriberCountMax | Integer | SubscriberCountMin | Upper bound when SubscriberCountMode is random. |
| TimeConstraintEnabled | Boolean | false | When true, pulls only run inside the time window defined below. When false, pulls run on every due interval. |
| AllowedDays | Array | (none) | Day-of-week abbreviations when pulls may run. Values: mon, tue, wed, thu, fri, sat, sun. Only applies when TimeConstraintEnabled is true; an empty list blocks all pulls. |
| DontSendBefore | String | 00:00 | Earliest time of day a pull may run, HH:MM. Only applies when TimeConstraintEnabled is true. |
| DontSendAfter | String | 23:59 | Latest time of day a pull may run, HH:MM. Only applies when TimeConstraintEnabled is true. |
| FrequencyCapEnabled | Boolean | false | When true, limits how often the same subscriber can be re-enrolled by this trigger. |
| FrequencyCapCount | Integer | 0 | Maximum number of enrollments per subscriber within the frequency-cap period. |
| FrequencyCapPeriod | Integer | 0 | Length of the frequency-cap window, combined with FrequencyCapUnit. |
| FrequencyCapUnit | String | days | Unit for FrequencyCapPeriod. Values: minutes, hours, days. |
The time window is evaluated in the journey owner's timezone. The top-level Run_Criteria / Run_Criteria_Operator (subscriber filtering) and Rate_Limit_Per_Hour / Rate_Limit_Per_Day parameters also apply to ScheduledPull journeys.
Key casing
The TriggerParameters keys above are case-insensitive on input — you may send them in any case (e.g. intervalValue, intervalvalue, or IntervalValue). They are normalized to the canonical PascalCase shown in the table before being stored, and journey.get always returns them in PascalCase. Sending the canonical PascalCase keys is recommended.
curl -X POST https://example.com/api/v1/journey \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.create",
"SessionID": "your-session-id",
"Name": "List Warm-up",
"Trigger": "ScheduledPull",
"Trigger_ListID": 123,
"TriggerParameters": {
"IntervalValue": 1,
"IntervalUnit": "hours",
"SubscriberCountMode": "random",
"SubscriberCountMin": 5,
"SubscriberCountMax": 25,
"TimeConstraintEnabled": true,
"AllowedDays": ["mon", "tue", "wed", "thu", "fri"],
"DontSendBefore": "09:00",
"DontSendAfter": "17:00",
"FrequencyCapEnabled": true,
"FrequencyCapCount": 1,
"FrequencyCapPeriod": 7,
"FrequencyCapUnit": "days"
},
"Notes": "Pull up to 25 subscribers hourly during business hours"
}'Clone a Journey
POST/api/v1/journey.cloneAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.clone |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey to clone |
| NewJourneyName | String | Yes | Name for the cloned journey |
curl -X POST https://example.com/api/v1/journey.clone \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.clone",
"SessionID": "your-session-id",
"JourneyID": 456,
"NewJourneyName": "Welcome Series Copy"
}'{
"Journey": {
"JourneyID": "789",
"JourneyName": "Welcome Series Copy",
"Trigger": "ListSubscription",
"TriggerParameters": {
"ListID": 123
},
"Status": "Disabled",
"Notes": "Copy of journey Welcome Series"
},
"Actions": []
}{
"Errors": [
{
"Code": 3,
"Message": "Journey not found"
}
]
}0: Success
1: Missing NewJourneyName parameter
2: Missing JourneyID parameter
3: Journey not found
4: Journey not cloned successfullyCopy Journey to Another User
POST/api/v1/journey.copytouserAPI Usage Notes
- Authentication required: Admin API Key
- This is an admin-only endpoint
- Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Resource Handling
When copying a journey to another user:
- Email templates referenced in
SendEmailactions are automatically copied to the target user. Duplicate emails are only copied once. - Other user-specific resources (lists, tags, custom fields, sender domains, SMS gateways, journey references) are reset to
0. The target user must configure these in the Journey Builder. - Journey trigger is always reset to
Manual. The target user must configure the trigger. - Journey status is always set to
Disabled.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journey.copytouser |
| AdminAPIKey | String | Yes | Admin API key for authentication |
| JourneyID | Integer | Yes | ID of the source journey to copy |
| SourceUserID | Integer | Yes | ID of the user who owns the source journey |
| TargetUserID | Integer | Yes | ID of the user to copy the journey to |
| NewJourneyName | String | No | Name for the copied journey. Defaults to "Copy of {original name}" |
curl -X POST https://example.com/api/v1/journey.copytouser \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.copytouser",
"AdminAPIKey": "your-admin-api-key",
"JourneyID": 456,
"SourceUserID": 1,
"TargetUserID": 2,
"NewJourneyName": "Welcome Series for User 2"
}'{
"Success": true,
"JourneyID": 789,
"EmailsCopied": [
{
"SourceEmailID": 123,
"NewEmailID": 456
}
],
"ResourcesReset": [
"SenderDomainID",
"TargetListID"
]
}{
"Success": false,
"Errors": [
{
"Code": 9,
"Message": "Journey not found for source user"
}
]
}0: Success
1: Missing JourneyID parameter
2: Missing SourceUserID parameter
3: Missing TargetUserID parameter
4: Invalid JourneyID (non-numeric)
5: Invalid SourceUserID (non-numeric)
6: Invalid TargetUserID (non-numeric)
7: Source user not found
8: Target user not found
9: Journey not found for source user
10: Failed to create journeyGet a Journey
GET/api/v1/journeyAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey to retrieve |
| StartDate | String | No | Start date for stats (YYYY-MM-DD) |
| EndDate | String | No | End date for stats (YYYY-MM-DD) |
| IncludeActivityCounters | Boolean | No | When truthy (1, true, yes, on), the JourneyStats block also includes LastTriggeredAt, LastActivityAt, and TotalEnrolledLifetime. Defaults to false so existing consumers see the same shape they do today. |
| EmailID | Integer | No | Scope JourneyStats.AggregatedEmailActions to a single SendEmail action on this journey (issue #2019). Must reference an action whose Action='SendEmail' and that belongs to this journey + caller. Reads the per-action ISP cache. Defaults to unset (journey-wide aggregate, unchanged). |
| ISP | String | No | Scope JourneyStats.AggregatedEmailActions to a single ISP domain (issue #2019). Must match /^[a-zA-Z0-9.-]+$/. Defaults to unset. Combine with EmailID to intersect (one action × one ISP). |
curl -X GET https://example.com/api/v1/journey \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.get",
"SessionID": "your-session-id",
"JourneyID": 456,
"StartDate": "2025-01-01",
"EndDate": "2025-01-31"
}'{
"JourneyID": "456",
"JourneyName": "Welcome Series",
"Trigger": "ListSubscription",
"TriggerParameters": {
"ListID": 123
},
"Status": "Enabled",
"Notes": "Onboarding journey",
"Actions": [],
"JourneyStats": {
"ActiveSubscribers": 150,
"TotalSubscribers": 500
}
}Optional activity counters
When IncludeActivityCounters=1 is passed, the JourneyStats block also includes:
| Field | Type | Description |
|---|---|---|
LastTriggeredAt | string or null | Most recent enrollment (MAX(oempro_journeys_entries.CreatedAt)), Y-m-d H:i:s format. null when the journey has never been triggered. |
LastActivityAt | string or null | Most recent log row of any kind (MAX(oempro_journeys_logs.CreatedAt)), same format. null when no activity has been recorded. |
TotalEnrolledLifetime | int | COUNT(DISTINCT RelSubscriberID) of subscribers who have ever been enrolled. Distinct from TotalSubscribers (which counts every enrollment row — a subscriber re-enrolled twice contributes 2 to TotalSubscribers but 1 to TotalEnrolledLifetime). |
These counters require two extra index-driven queries (one on journeys_entries, one on journeys_logs) and are off by default to keep the existing latency profile.
Per-action revenue fields (issue #2010)
Each SendEmail entry in the Actions array also exposes two top-level revenue fields, sourced from the same daily cache that powers the existing Stats.TotalRevenue and DailyStats[].TotalRevenue:
| Field | Type | Description |
|---|---|---|
Revenue | float | Total revenue attributed to this action over the response window, in currency units (dollars). Same scale as JourneyStats.TotalRevenue. |
DaysRevenue | array | Daily revenue series: [{ "Date": "YYYY-MM-DD", "Amount": 0.0 }, ...] sorted ascending by Date. Zero-amount days are included so consumers can chart a continuous x-axis without gap-fill logic. |
Non-SendEmail actions (Wait, Decision, AddTag, etc.) do not have these fields — consistent with how Stats and DailyStats already behave for non-revenue-generating actions. No extra queries are required to produce the fields; they reuse data the response already computes.
Filtered AggregatedEmailActions (issue #2019)
When EmailID or ISP is passed, JourneyStats.AggregatedEmailActions is computed from the per-ISP cache instead of the journey-wide cache. The same 11 keys are returned in both modes for shape stability:
| Field | Behavior under filter |
|---|---|
SendCount, DeliveryCount, OpenCount, ClickCount, BounceCount, UnsubscribeCount, SpamComplaintCount | Summed across rows matching the filter slice. |
TotalRevenue | Summed and converted from cents to currency units (matches the unfiltered shape). |
ConversionCount, BrowserViewCount, ForwardCount | Always returned as 0 under filter (the per-ISP cache does not track these three counters today). |
Time window: the filtered AggregatedEmailActions is always an all-time aggregate — same semantics as the unfiltered path. StartDate and EndDate only drive the date-windowed AggregatedDaysEmailActions sub-block, never the lifetime summary. When neither EmailID nor ISP is set, the response is byte-identical to today's contract.
{
"Errors": [
{
"Code": 3,
"Message": "Journey not found"
}
]
}0: Success
1: Missing JourneyID parameter
2: Invalid JourneyID parameter
3: Journey not found
4: Invalid StartDate format
5: Invalid EndDate format
6: StartDate must be before EndDate
7: Invalid EmailID parameter (not a positive integer, or not a SendEmail action on this journey)
8: Invalid ISP parameter (must match /^[a-zA-Z0-9.-]+$/):::
List Journeys
GET/api/v1/journeysAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.list |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| StatsStartDate | String | No | Start date for stats (YYYY-MM-DD) |
| StatsEndDate | String | No | End date for stats (YYYY-MM-DD) |
| SkipStats | Boolean | No | When truthy (1, true, yes), the per-row JourneyStats block is omitted entirely. Default: false (full stats are returned). Empty string is treated as absent. |
| IncludeActivityCounters | Boolean | No | When truthy, each row's JourneyStats block gains LastTriggeredAt, LastActivityAt, and TotalEnrolledLifetime (see the journey.get reference for definitions). Batched in two queries total regardless of journey count. When combined with SkipStats=1, the entire JourneyStats block stays suppressed — counters are not produced standalone. Default: false. |
About SkipStats
This flag is intended for callers that only need the flat list of journeys (e.g. dropdown pickers in segment rule-builders) and don't display stats. When set, the endpoint skips four JourneyStats queries per journey plus the per-row stats join, so it's substantially cheaper for users with many journeys.
When SkipStats=1, consumers must check array_key_exists('JourneyStats', $row) rather than reading $row['JourneyStats'] — the key is omitted, not set to null or [].
Date validation (StatsStartDate, StatsEndDate) still runs even with SkipStats=1, so malformed dates are rejected the same way they would be without the flag.
curl -X GET https://example.com/api/v1/journeys \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.list",
"SessionID": "your-session-id",
"StatsStartDate": "2025-01-01",
"StatsEndDate": "2025-01-31"
}'curl -X GET https://example.com/api/v1/journeys \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.list",
"SessionID": "your-session-id",
"SkipStats": 1
}'{
"Journeys": [
{
"JourneyID": "456",
"JourneyName": "Welcome Series",
"Trigger": "ListSubscription",
"TriggerParameters": {
"ListID": 123
},
"Status": "Enabled",
"JourneyStats": {
"ActiveSubscribers": 150,
"TotalSubscribers": 500,
"AggregatedEmailActions": {},
"AggregatedDaysEmailActions": [],
"TotalRevenue": 0,
"DaysRevenue": []
}
}
]
}{
"Journeys": [
{
"JourneyID": "456",
"JourneyName": "Welcome Series",
"Trigger": "ListSubscription",
"TriggerParameters": {
"ListID": 123
},
"Status": "Enabled"
}
]
}{
"Errors": [
{
"Code": 4,
"Message": "Invalid StatsStartDate format"
}
]
}0: Success
4: Invalid StatsStartDate format
5: Invalid StatsEndDate format
6: StatsStartDate must be before StatsEndDateList SendEmail Actions Across Journeys
GET/api/v1/journey.sendemailactionsReturns a flat list of every SendEmail journey action belonging to the authenticated user, optionally narrowed to a single journey. Designed for segment rule-builder pickers (rule type journey-email-action) that need every choosable email-send action in a single round trip — replacing the legacy N+1 of Journey.List plus per-journey Journey.Get.
API Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.sendemailactions |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | No | Narrow the result to a single journey. When omitted (or empty string), all of the user's journeys are scanned. A JourneyID belonging to a different user silently returns Actions: [] (not an error). |
| IncludeDisabled | Boolean | No | When truthy (1, true, yes), actions belonging to journeys with Status='Disabled' are included. Default: false. Empty string is treated as absent. |
| IncludeUnpublished | Boolean | No | When truthy, actions whose own Published flag is false are included. Default: false. Empty string is treated as absent. |
Filter Defaults
By default the endpoint returns only actions that are (a) of type SendEmail, (b) belonging to a journey whose Status is Enabled, and (c) themselves Published='true' — matching what the legacy segment rule-builder picker shows today. The two Include* flags are escape hatches for admin or debugging tooling.
Boolean coercion uses filter_var(FILTER_VALIDATE_BOOLEAN), so 1 / true / yes / on opt in. Anything outside that allow-list (including 2, foo, empty string) falls back to the conservative default.
curl -X GET https://example.com/api/v1/journey.sendemailactions \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.sendemailactions",
"SessionID": "your-session-id"
}'curl -X GET https://example.com/api/v1/journey.sendemailactions \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.sendemailactions",
"SessionID": "your-session-id",
"JourneyID": 18
}'curl -X GET https://example.com/api/v1/journey.sendemailactions \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.sendemailactions",
"SessionID": "your-session-id",
"IncludeDisabled": 1,
"IncludeUnpublished": 1
}'{
"Success": true,
"Actions": [
{
"ActionID": 412,
"JourneyID": 18,
"JourneyName": "Welcome Series",
"EmailName": "Day 1 — Welcome",
"Subject": "Welcome to Acme",
"OrderNo": 1,
"Published": true
},
{
"ActionID": 415,
"JourneyID": 18,
"JourneyName": "Welcome Series",
"EmailName": "Day 3 — Tips",
"Subject": "Three quick tips to get started",
"OrderNo": 2,
"Published": true
}
]
}{
"Errors": [
{
"Code": 1,
"Message": "Invalid JourneyID parameter"
}
]
}0: Success
1: Invalid JourneyID parameterPer-row fields:
| Field | Type | Description |
|---|---|---|
| ActionID | Integer | Primary key from oempro_journeys_actions. This is the value the segment rule-builder writes into rule.value for the journey-email-action rule type. |
| JourneyID | Integer | Owning journey. |
| JourneyName | String | Owning journey's name (HTML-decoded). |
| EmailName | String | The referenced email's name. Empty string when the email row is missing (orphan action). |
| Subject | String | The referenced email's subject line. Empty string when the email row is missing. |
| OrderNo | Integer | Action ordering within its parent branch. Useful for ordering choices within a journey, but not globally unique across journeys. |
| Published | Boolean | Whether the action itself is published on the journey canvas. |
EmailName / Subject orphans
The endpoint joins to oempro_emails via the EmailID stored in the action's ActionParameters. If the referenced email row no longer exists (manually deleted, mid-rebuild, etc.) the action is still returned with EmailName: "" and Subject: "" — the picker should display a fallback label rather than dropping the row.
Update a Journey
PATCH/api/v1/journeyAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.update |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey to update |
| Name | String | No | Updated journey name |
| Notes | String | No | Updated journey notes |
| Trigger | String | No | Updated trigger type. Possible values: Manual, ListSubscription, ListUnsubscription, EmailOpen, EmailConversion, EmailLinkClick, Tag, UnTag, CustomFieldValueChanged, RevenueHit, JourneyCompleted, ScheduledPull, WebsiteEvent_pageView, WebsiteEvent_identify, WebsiteEvent_customEvent, WebsiteEvent_conversion. See Scheduled Pull Trigger for its additional parameters. |
| Trigger_ListID | Integer | No | Updated list ID for triggers |
| TriggerParameters | Object | No | Updated trigger-specific settings. For the ScheduledPull trigger see Scheduled Pull Trigger. |
| Trigger_EmailID | Integer | No | Updated email ID for triggers |
| Trigger_Value | String/Integer | No | Updated trigger value |
| Trigger_Criteria | Array | No | Updated trigger criteria |
| Run_Criteria | Array | No | Updated run criteria |
| Run_Criteria_Operator | String | No | Updated run criteria operator. Possible values: and, or (default: and) |
| Rate_Limit_Per_Hour | Integer | No | Updated hourly rate limit |
| Rate_Limit_Per_Day | Integer | No | Updated daily rate limit |
curl -X PATCH https://example.com/api/v1/journey \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.update",
"SessionID": "your-session-id",
"JourneyID": 456,
"Name": "Welcome Series V2",
"Notes": "Updated onboarding journey"
}'{
"Journey": {
"JourneyID": "456",
"JourneyName": "Welcome Series V2",
"Trigger": "ListSubscription",
"TriggerParameters": {
"ListID": 123
},
"Status": "Enabled",
"Notes": "Updated onboarding journey",
"UpdatedAt": "2025-01-15 11:00:00"
}
}{
"Errors": [
{
"Code": 10,
"Message": "Journey not found"
}
]
}0: Success
1: Missing JourneyID parameter
2: Invalid JourneyID parameter
4: Missing Trigger_ListID parameter
5: Invalid Trigger_ListID parameter
6: Trigger_ListID matching record not found
7: Missing Trigger_EmailID parameter
8: Invalid Trigger_EmailID parameter
9: Trigger_EmailID matching record not found
10: Journey not found
11: Trigger_Value matching record not found
12: Invalid Trigger_Value parameter (CustomFieldValueChanged)
13: Trigger_Value matching record not found (CustomFieldValueChanged)
14: Invalid Trigger_Value parameter (RevenueHit)
15: Missing Trigger_Value parameter (RevenueHit)
16: Invalid Trigger_Value parameter (JourneyCompleted)
17: Trigger_Value matching record not found (JourneyCompleted)
18: Invalid rate_limit_per_hour parameter
19: Invalid rate_limit_per_day parameter
20: Missing or invalid Trigger_ListID parameter for ScheduledPull trigger
21: Trigger_ListID matching record not found (ScheduledPull)
22: A journey cannot be triggered by its own completion (JourneyCompleted)Delete a Journey
POST/api/v1/journey.deleteAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.delete |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey to delete |
curl -X POST https://example.com/api/v1/journey.delete \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.delete",
"SessionID": "your-session-id",
"JourneyID": 456
}'{
"JourneyID": 456
}{
"Errors": [
{
"Code": 3,
"Message": "Journey not found"
}
]
}0: Success
1: Missing JourneyID parameter
2: Invalid JourneyID parameter
3: Journey not foundDelete Multiple Journeys
POST/api.phpAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Delete - Legacy endpoint access via
/api.phponly (no v1 REST alias configured)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journeys.delete |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| Journeys | String | Yes | Comma-separated journey IDs to delete |
curl -X POST https://example.com/api.php \
-H "Content-Type: application/json" \
-d '{
"Command": "journeys.delete",
"SessionID": "your-session-id",
"Journeys": "456,789,101"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": ""
}{
"Success": false,
"ErrorCode": [1]
}0: Success
1: Missing Journeys parameterEnable a Journey
GET/api/v1/journey.enableAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.enable |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey to enable |
curl -X GET https://example.com/api/v1/journey.enable \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.enable",
"SessionID": "your-session-id",
"JourneyID": 456
}'{
"Journey": {
"JourneyID": "456",
"JourneyName": "Welcome Series",
"Trigger": "ListSubscription",
"Status": "Enabled",
"UpdatedAt": "2025-01-15 12:00:00"
}
}{
"Errors": [
{
"Code": 4,
"Message": "Journey is already enabled"
}
]
}0: Success
1: Missing JourneyID parameter
2: Invalid JourneyID parameter
3: Journey not found
4: Journey is already enabledDisable a Journey
GET/api/v1/journey.disableAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.disable |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey to disable |
curl -X GET https://example.com/api/v1/journey.disable \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.disable",
"SessionID": "your-session-id",
"JourneyID": 456
}'{
"Journey": {
"JourneyID": "456",
"JourneyName": "Welcome Series",
"Trigger": "ListSubscription",
"Status": "Disabled",
"UpdatedAt": "2025-01-15 13:00:00"
}
}{
"Errors": [
{
"Code": 4,
"Message": "Journey is already disabled"
}
]
}0: Success
1: Missing JourneyID parameter
2: Invalid JourneyID parameter
3: Journey not found
4: Journey is already disabledUpdate Journey Actions
Journey Action Types
For detailed documentation of each action type and its parameters, see Journey Actions.
/api/v1/journey.actionsAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.actions.update |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey |
| Actions | Array | Yes | Array of action objects to update |
curl -X PATCH https://example.com/api/v1/journey.actions \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.actions.update",
"SessionID": "your-session-id",
"JourneyID": 456,
"Actions": [
{
"action": "SendEmail",
"emailid": 123,
"from": {
"name": "Support",
"email": "support@example.com"
}
}
]
}'{
"JourneyID": "456",
"JourneyName": "Welcome Series",
"Actions": [
{
"ActionID": "789",
"Action": "SendEmail",
"ActionParameters": {
"EmailID": 123,
"From": {
"Name": "Support",
"Email": "support@example.com"
}
}
}
]
}{
"Errors": [
{
"Code": 5,
"Message": "Journey not found"
}
]
}0: Success
1: Missing JourneyID parameter
2: Missing Actions parameter
3: Invalid JourneyID parameter
4: Invalid JourneyID parameter (Actions must be array)
5: Journey not found
6: Invalid action type or Journey not foundUpdate Actions Published Status
PATCH/api/v1/journey.actions.publishedAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.actions.published |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey |
| Actions | Array | Yes | Array of action objects with published status |
curl -X PATCH https://example.com/api/v1/journey.actions.published \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.actions.published",
"SessionID": "your-session-id",
"JourneyID": 456,
"Actions": [
{
"actionid": 789,
"published": "true"
}
]
}'{
"JourneyID": "456",
"JourneyName": "Welcome Series",
"Actions": [
{
"ActionID": "789",
"Published": "true"
}
]
}{
"Errors": [
{
"Code": 6,
"Message": "Action not found"
}
]
}0: Success
1: Missing JourneyID parameter
2: Missing Actions parameter
3: Invalid JourneyID parameter
4: Invalid JourneyID parameter (Actions must be array)
5: Journey not found
6: Action not found
7: Journey not found after updateGet Action Subscribers
GET/api/v1/journey.action.subscribersAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - 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: journey.action.subscribers |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | ID of the journey |
| ActionID | Integer | Yes | ID of the action |
| FilterJSON | String | No | JSON array of filter items. Each item should be one of: opened, clicked, converted, browser_viewed, forwarded, unsubscribed, bounced, spam_complaint |
| Operator | String | No | Filter operator. Possible values: AND, OR. Only used when FilterJSON is provided |
| RecordsPerRequest | Integer | No | Number of records per page (default: 25) |
| RecordsFrom | Integer | No | Starting record offset (default: 0) |
| OrderField | String | No | Field to order by (default: EmailAddress) |
| OrderType | String | No | Order direction. Possible values: ASC, DESC (default: ASC) |
curl -X GET https://example.com/api/v1/journey.action.subscribers \
-H "Content-Type: application/json" \
-d '{
"Command": "journey.action.subscribers",
"SessionID": "your-session-id",
"JourneyID": 456,
"ActionID": 789,
"RecordsPerRequest": 25,
"RecordsFrom": 0,
"OrderField": "EmailAddress",
"OrderType": "ASC"
}'{
"Success": true,
"ErrorCode": 0,
"ErrorText": "",
"Subscribers": [
{
"SubscriberID": "101",
"EmailAddress": "user@example.com",
"Suppressed": false
}
],
"TotalSubscribers": 150
}{
"Success": false,
"ErrorCode": [
{
"Code": 5,
"Message": "Journey not found"
}
]
}0: Success
1: Missing JourneyID parameter
2: Missing ActionID parameter
3: Invalid JourneyID parameter
4: Invalid ActionID parameter
5: Invalid FilterJSON parameter (invalid JSON)
6: Invalid FilterJSON value (unrecognized filter item)
7: Invalid Operator valueINFO
After validation, the following business logic errors may also be returned:
5: Journey not found (HTTP 404)6: Action not found (HTTP 404)
:::
Get Per-ISP Engagement Stats for a Journey
GET/api/v1/journey.stats.byispAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns the per-ISP engagement rollup for a single journey within an optional date range. Mirrors the data the web UI's "By ISP" tab renders on the journey overview page. Reads the daily-cached ISP-level stats populated by the journey delivery pipeline.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journey.stats.byisp |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | Journey ID to fetch ISP-level stats for. Must be a positive integer and owned by the caller. |
| StartDate | String | No | Range start in YYYY-MM-DD format. Defaults to 30 days ago. |
| EndDate | String | No | Range end in YYYY-MM-DD format. Defaults to today. |
| EmailID | Integer | No | Scope the rollup to a single SendEmail action on this journey (issue #2019). Must reference an action whose Action='SendEmail' and that belongs to this journey + caller. When set, reads oempro_journeys_actions_daily_cached_data_by_isp instead of the journey-level cache. Defaults to unset. |
curl -X GET "https://example.com/api/v1/journey.stats.byisp?JourneyID=123&StartDate=2026-04-17&EndDate=2026-05-17" \
-H "APIKey: your-api-key"{
"Success": true,
"ByISP": [
{
"Domain": "gmail.com",
"Sent": 1000,
"Delivered": 950,
"Opened": 400,
"Clicked": 80,
"Bounced": 25,
"Unsubscribed": 5,
"Complained": 1
},
{
"Domain": "yahoo.com",
"Sent": 500,
"Delivered": 480,
"Opened": 180,
"Clicked": 30,
"Bounced": 12,
"Unsubscribed": 2,
"Complained": 0
}
]
}{
"Errors": [
{ "Code": 3, "Message": "Journey not found" }
]
}0: Success
1: Missing JourneyID parameter
2: Invalid JourneyID parameter (must be a positive integer)
3: Journey not found (HTTP 404)
4: Invalid StartDate format
5: Invalid EndDate format
6: StartDate must be before EndDate
7: Invalid EmailID parameter (not a positive integer, or not a SendEmail action on this journey)Get Per-Action Engagement Stats for a Journey
GET/api/v1/journey.stats.byactionAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns per-SendEmail-action engagement stats for a journey, optionally scoped by date range, single email (EmailID), and/or ISP domain. Closes the scoping triangle alongside journey.stats.byisp (issue #2007) and the journey.get filters (issue #2019) — the web UI's per-step overview cards render the same data filtered, this endpoint exposes it to API consumers.
Each row contains a lifetime-style Stats block for the requested window plus a DailyStats time series zero-filled across every date in the window (consumers can chart a continuous x-axis without gap-fill logic).
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journey.stats.byaction |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyID | Integer | Yes | Journey ID. Must be a positive integer and owned by the caller. |
| StartDate | String | No | Range start in YYYY-MM-DD format. Defaults to 30 days ago. |
| EndDate | String | No | Range end in YYYY-MM-DD format. Defaults to today. |
| EmailID | Integer | No | Restrict the response to a single SendEmail action's ActionID. Must reference an action with Action='SendEmail' on this journey. |
| ISP | String | No | Scope all returned rows to one ISP domain. Must match /^[a-zA-Z0-9.-]+$/. When set, reads the per-action × per-ISP cache. |
curl -X GET "https://example.com/api/v1/journey.stats.byaction?JourneyID=123&StartDate=2026-04-17&EndDate=2026-05-17&ISP=gmail.com" \
-H "APIKey: your-api-key"{
"Success": true,
"Actions": [
{
"ActionID": 501,
"Action": "SendEmail",
"EmailID": 95,
"EmailName": "Welcome Email",
"OrderNo": 1,
"Stats": {
"SendCount": 1000,
"DeliveryCount": 950,
"OpenCount": 400,
"ClickCount": 80,
"BounceCount": 25,
"UnsubscribeCount": 5,
"SpamComplaintCount": 1,
"TotalRevenue": 123.45
},
"DailyStats": [
{ "Date": "2026-04-17", "SendCount": 0, "OpenCount": 0, "ClickCount": 0, "TotalRevenue": 0.0 },
{ "Date": "2026-04-18", "SendCount": 100, "OpenCount": 40, "ClickCount": 8, "TotalRevenue": 12.34 }
]
}
]
}{
"Errors": [
{ "Code": 3, "Message": "Journey not found" }
]
}0: Success
1: Missing JourneyID parameter
2: Invalid JourneyID parameter (must be a positive integer)
3: Journey not found (HTTP 404)
4: Invalid StartDate format
5: Invalid EndDate format
6: StartDate must be before EndDate
7: Invalid EmailID parameter (not a positive integer, or not a SendEmail action on this journey)
8: Invalid ISP parameter (must match /^[a-zA-Z0-9.-]+$/)Field semantics
Statsis a lifetime aggregate for the requested window (same window applied across all returned actions).DailyStatsis a per-day series. Days with no activity are zero-filled so consumers can chart a continuous x-axis.TotalRevenueon bothStatsandDailyStatsis in currency units (cents/100), matchingjourney.get'sAggregatedEmailActions.TotalRevenueshape.EmailIDin each row is the underlyingoempro_emails.EmailIDextracted from the action'sActionParameters.EmailID. Note that the input parameter also calledEmailIDrefers to the journey action'sActionID(consistent withjourney.getfrom issue #2019), not the underlying email's ID.Actionis always"SendEmail"— non-SendEmail actions (Wait, Decision, AddTag, etc.) are excluded since they don't produce engagement data.- When
EmailIDis omitted, everySendEmailaction on the journey is returned, ordered byOrderNoascending. - An empty journey (no
SendEmailactions) returnsActions: []withSuccess: true.
Get Account-Level Journey Benchmark
GET/api/v1/account.journey.benchmarkAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns Sent-weighted engagement averages aggregated across every journey owned by the calling user within an optional date range. Parallels emailgateway.accountstats but for the journey module. Useful for showing a "your average vs this journey" benchmark in dashboards.
All rates are weighted by SendCount (a 9 000-send journey contributes proportionally more than a 100-send journey) — a naive arithmetic mean would over-weight low-volume journeys.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: account.journey.benchmark |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| StartDate | String | No | Range start in YYYY-MM-DD format. Defaults to 30 days ago. |
| EndDate | String | No | Range end in YYYY-MM-DD format. Defaults to today. |
curl -X GET "https://example.com/api/v1/account.journey.benchmark?StartDate=2026-04-17&EndDate=2026-05-17" \
-H "APIKey: your-api-key"{
"Success": true,
"StartDate": "2026-04-17",
"EndDate": "2026-05-17",
"Benchmark": {
"OpenRate": 0.5055,
"ClickRate": 0.0825,
"ClickToOpenRate": 0.1632,
"BounceRate": 0.0125,
"UnsubscribeRate": 0.0021,
"ComplaintRate": 0.0001,
"RevenuePerSubscriber": 0.42,
"JourneyCount": 7,
"TotalSent": 18420
}
}{
"Errors": [
{ "Code": 3, "Message": "StartDate must not be after EndDate" }
]
}0: Success
1: Invalid StartDate format
2: Invalid EndDate format
3: StartDate must not be after EndDateINFO
Rates are returned as decimal proportions, not percentages. For example, OpenRate: 0.5055 means 50.55%. Multiply by 100 for display. JourneyCount reflects journeys that had at least one send in the window — journeys with zero sends do not contribute. RevenuePerSubscriber is denominated in the same currency the journey was stored in (cents on the wire are converted to currency units server-side).
Strict date validation (differs from emailgateway.accountstats)
This endpoint rejects invalid date inputs (StartDate=2026-02-30, wrong separator, etc.) with error codes 1/2. The sibling emailgateway.accountstats endpoint silently coerces invalid dates back to its defaults instead of erroring. If you target both endpoints, validate input client-side before calling to keep behavior consistent.
Bulk Enable Journeys
POST/api/v1/journeys.enableAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Flips status to Enabled for each owned journey currently in Disabled state. Per-ID processing — skipped IDs (cross-tenant, not found, already-Enabled status conflict) land in FailedJourneyIDs rather than failing the whole call.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journeys.enable |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyIDs | String | Yes | Comma-separated list of positive integer JourneyIDs (e.g. 12,34,56) |
curl -X POST "https://example.com/api/v1/journeys.enable" \
-H "APIKey: your-api-key" \
-d "JourneyIDs=12,34,56"{
"Success": true,
"ProcessedJourneyIDs": [12, 34],
"FailedJourneyIDs": [56]
}{
"Errors": [
{ "Code": 1, "Message": "Missing JourneyIDs parameter" }
]
}0: Success
1: Missing JourneyIDs parameter
2: Invalid JourneyIDs parameter (no positive integers after parsing)Bulk Disable Journeys
POST/api/v1/journeys.disableAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Mirror of journeys.enable but flips status from Enabled to Disabled. Skipped IDs (cross-tenant, not found, already-Disabled status conflict) land in FailedJourneyIDs.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journeys.disable |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyIDs | String | Yes | Comma-separated list of positive integer JourneyIDs |
Response shape and error codes are identical to journeys.enable.
Bulk Clone Journeys
POST/api/v1/journeys.cloneAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Creates a Disabled copy of each owned source journey, including all actions (parent-child relationships preserved). Email templates and resource IDs are not copied — the clones reference the same underlying resources as the originals. (Use journey.copytouser for cross-tenant cloning with full resource duplication.)
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journeys.clone |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| JourneyIDs | String | Yes | Comma-separated list of positive integer JourneyIDs to clone |
| NameSuffix | String | No | Suffix appended to source name with a leading space. Defaults to (copy) — output name: "Original Name (copy)". |
curl -X POST "https://example.com/api/v1/journeys.clone" \
-H "APIKey: your-api-key" \
-d "JourneyIDs=12,34&NameSuffix=- backup"{
"Success": true,
"ProcessedJourneyIDs": [12, 34],
"FailedJourneyIDs": [],
"ClonedJourneys": [
{ "SourceJourneyID": 12, "NewJourneyID": 1234 },
{ "SourceJourneyID": 34, "NewJourneyID": 1235 }
]
}{
"Errors": [
{ "Code": 1, "Message": "Missing JourneyIDs parameter" }
]
}0: Success
1: Missing JourneyIDs parameter
2: Invalid JourneyIDs parameter (no positive integers after parsing)Partial-success contract
All three endpoints (journeys.enable, journeys.disable, journeys.clone) return Success: true whenever the call itself completed — per-ID outcomes are split into ProcessedJourneyIDs and FailedJourneyIDs. Validation errors (missing or unusable JourneyIDs) are the only conditions that fail the whole call with HTTP 422.
Submit a Journey CSV Export
POST/api/v1/journey.exportAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Enqueues an async CSV export of the caller's journeys with rolled-up stats for a given date range and status filter. Mirrors the pattern used by subscribers.export — the worker processes the job in the background; callers should poll journey.export.get (or use the download=1 flag once the job has completed).
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journey.export.submit |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| StatsStartDate | String | No | YYYY-MM-DD start of the stats window. Defaults to 30 days ago. |
| StatsEndDate | String | No | YYYY-MM-DD end of the stats window. Defaults to today. |
| Status | String | No | Filter by journey status. Possible values: Enabled, Disabled, all. Defaults to all. |
| IncludeActions | Boolean | No | When truthy, the CSV includes one row per SendEmail action under each journey (mirrors the web UI's expanded view). Defaults to false. |
curl -X POST "https://example.com/api/v1/journey.export" \
-H "APIKey: your-api-key" \
-d "StatsStartDate=2026-04-17&StatsEndDate=2026-05-17&Status=Enabled&IncludeActions=1"{
"Success": true,
"ExportID": 1234
}{
"Errors": [
{ "Code": 3, "Message": "StatsStartDate must not be after StatsEndDate" }
]
}0: Success
1: Invalid StatsStartDate format
2: Invalid StatsEndDate format
3: StatsStartDate must not be after StatsEndDate
4: Invalid Status value (expected: Enabled, Disabled, or all)Poll / Download a Journey CSV Export
GET/api/v1/journey.exportAPI Usage Notes
- Authentication required: User API Key
- Required permissions:
Campaign.Create - Rate limit: 100 requests per 60 seconds
- Legacy endpoint access via
/api.phpis also supported
Returns the JSON status of an export job, or streams the CSV file when download=1 and the job is Completed. Cross-tenant or cross-module ExportIDs are rejected — this endpoint only serves jobs with Module='JourneyExport'.
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| Command | String | Yes | API command: journey.export.get |
| SessionID | String | No | Session ID obtained from login |
| APIKey | String | No | API key for authentication |
| ExportID | Integer | Yes | The export job ID returned by journey.export.submit (positive integer) |
| download | Boolean | No | When truthy and Status=Completed, streams the file with Content-Type: text/csv and a Content-Disposition: attachment header. Otherwise returns the JSON envelope. |
curl -X GET "https://example.com/api/v1/journey.export?ExportID=1234" \
-H "APIKey: your-api-key"curl -X GET "https://example.com/api/v1/journey.export?ExportID=1234&download=1" \
-H "APIKey: your-api-key" \
-o journey-export.csv{
"Success": true,
"ExportJob": {
"ExportID": 1234,
"Module": "JourneyExport",
"Status": "Completed",
"ExportOptions": {
"Command": "ExportJourneys",
"StatsStartDate": "2026-04-17",
"StatsEndDate": "2026-05-17",
"Status": "Enabled",
"IncludeActions": true
},
"SubmittedAt": "2026-05-18 12:00:00",
"StartedAt": "2026-05-18 12:00:05",
"UpdatedAt": "2026-05-18 12:00:30",
"FinishedAt": "2026-05-18 12:00:30",
"ExpiresAt": "2026-05-25 12:00:00",
"DownloadSize": 4096
}
}{
"Errors": [
{ "Code": 5, "Message": "Export job is not completed yet" }
]
}0: Success
1: Missing ExportID parameter
2: Invalid ExportID parameter
3: Export job not found (HTTP 404)
4: Wrong module (job exists but is not a JourneyExport, HTTP 404)
5: Download requested but Status is not Completed (HTTP 409)Async lifecycle
Status flows through Pending → Processing → Completed (or Failed). The background export worker picks up Pending jobs in submission order. ExpiresAt is currently advisory — the export file isn't auto-cleaned up today, so the field is provided for forward-compat with future retention policy.

Help Portal