curl --request POST \
--url https://api.onesignal.com/apps/{app_id}/journeys \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"name": "Welcome series",
"description": "Onboard new users over their first week.",
"audience": {
"kind": "segment",
"included_segment_ids": [
"3f7c1e90-0000-0000-0000-000000000001"
],
"excluded_segment_ids": []
},
"nodes": [
{
"kind": "send_push",
"template_id": "9a8b7c6d-0000-0000-0000-000000000001"
},
{
"kind": "wait",
"duration_seconds": 86400
},
{
"kind": "send_email",
"template_id": "9a8b7c6d-0000-0000-0000-000000000002"
}
]
}
'import Onesignal from '@onesignal/node-onesignal';
const configuration = Onesignal.createConfiguration({
restApiKey: 'YOUR_REST_API_KEY',
});
const apiInstance = new Onesignal.DefaultApi(configuration);
// string | Your OneSignal App ID in UUID v4 format.
const appId: string = "YOUR_APP_ID";
// CreateJourneyRequest
const createJourneyRequest: Onesignal.CreateJourneyRequest = {
name: "name_example",
description: "description_example",
audience: {
kind: "segment",
included_segment_ids: [
"included_segment_ids_example",
],
excluded_segment_ids: [
"excluded_segment_ids_example",
],
future_additions_only: true,
name: "name_example",
attributes: [
[
{
key: "key_example",
operator: "equal",
value: "value_example",
},
],
],
},
early_exit: {
rules: {
on_segment: {
included_segment_ids: [
"included_segment_ids_example",
],
},
when_not_in_audience: true,
on_session: true,
on_event: {
name: "name_example",
},
},
tag_on_early_exit: {
"key": "key_example",
},
},
reentry_rules: {
duration_seconds: 600,
},
schedule: {
start_at: "start_at_example",
stop_at: "stop_at_example",
error: "error_example",
},
nodes: [
{
id: "id_example",
kind: "wait",
client_node_id: "client_node_id_example",
annotation: "annotation_example",
duration_seconds: 60,
relative_to: "schedule_in_timezone",
windows: [
{
start: null,
end: null,
day_of_week: 1,
},
],
time_zone: "time_zone_example",
use_user_time_zone: true,
template_id: "template_id_example",
iam_id: "iam_id_example",
user_ttl_seconds: 1,
webhook_id: "webhook_id_example",
assignments: {
"key": "key_example",
},
randomize_on_entry: true,
branches: [
{
id: "id_example",
condition: {
kind: "segment_membership",
included_segment_ids: [
"included_segment_ids_example",
],
excluded_segment_ids: [
"excluded_segment_ids_example",
],
action: "received",
sending_node_id: "sending_node_id_example",
client_node_id: "client_node_id_example",
name: "name_example",
attributes: [
[
{
key: "key_example",
operator: "equal",
value: "value_example",
},
],
],
entry_event_match_attributes: [
{},
],
},
weight: 3.14,
nodes: [
,
],
},
],
expiration: {
duration_seconds: 60,
exits: true,
},
},
],
};
try {
const response = await apiInstance.createJourney(appId, createJourneyRequest);
console.log(response);
} catch (e) {
if (e instanceof Onesignal.ApiException) {
// `e.errorMessages` flattens any error-envelope shape to a `string[]`;
// the raw parsed body remains on `e.body`.
console.error("createJourney failed: HTTP " + e.code, e.errorMessages);
} else {
throw e;
}
}import onesignal
from onesignal.api import default_api
from onesignal.models import *
from pprint import pprint
# See configuration.py for a list of all supported configuration parameters.
# Some of the OneSignal endpoints require ORGANIZATION_API_KEY token for authorization, while others require REST_API_KEY.
# We recommend adding both of them in the configuration page so that you will not need to figure it out yourself.
configuration = onesignal.Configuration(
rest_api_key = "YOUR_REST_API_KEY", # App REST API key required for most endpoints
organization_api_key = "YOUR_ORGANIZATION_API_KEY" # Organization key is only required for creating new apps and other top-level endpoints
)
# Enter a context with an instance of the API client
with onesignal.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = default_api.DefaultApi(api_client)
app_id = "YOUR_APP_ID" # Your OneSignal App ID in UUID v4 format.
create_journey_request = CreateJourneyRequest(
name="name_example",
description="description_example",
audience=JourneyAudience(
kind="segment",
included_segment_ids=[
"included_segment_ids_example",
],
excluded_segment_ids=[
"excluded_segment_ids_example",
],
future_additions_only=True,
name="name_example",
attributes=JourneyEventTriggerAttributes([
[
JourneyEventAttribute(
key="key_example",
operator="equal",
value="value_example",
),
],
]),
),
early_exit=JourneyEarlyExit(
rules=JourneyEarlyExitRules(
on_segment=JourneyEarlyExitRulesOnSegment(
included_segment_ids=[
"included_segment_ids_example",
],
),
when_not_in_audience=True,
on_session=True,
on_event=JourneyEarlyExitRulesOnEvent(
name="name_example",
),
),
tag_on_early_exit={
"key": "key_example",
},
),
reentry_rules=JourneyReentryRules(
duration_seconds=600,
),
schedule=JourneySchedule(
start_at="start_at_example",
stop_at="stop_at_example",
error="error_example",
),
nodes=[
JourneyNode(
id="id_example",
kind="wait",
client_node_id="client_node_id_example",
annotation="annotation_example",
duration_seconds=60,
relative_to="schedule_in_timezone",
windows=[
JourneyTimeWindow(
start=None,
end=None,
day_of_week=1,
),
],
time_zone="time_zone_example",
use_user_time_zone=True,
template_id="template_id_example",
iam_id="iam_id_example",
user_ttl_seconds=1,
webhook_id="webhook_id_example",
assignments={
"key": "key_example",
},
randomize_on_entry=True,
branches=[
JourneyBranch(
id="id_example",
condition=JourneyCondition(
kind="segment_membership",
included_segment_ids=[
"included_segment_ids_example",
],
excluded_segment_ids=[
"excluded_segment_ids_example",
],
action="received",
sending_node_id="sending_node_id_example",
client_node_id="client_node_id_example",
name="name_example",
attributes=JourneyEventTriggerAttributes([
[
JourneyEventAttribute(
key="key_example",
operator="equal",
value="value_example",
),
],
]),
entry_event_match_attributes=[
{},
],
),
weight=3.14,
nodes=[
JourneyNode(),
],
),
],
expiration=JourneyWaitUntilExpiration(
duration_seconds=60,
exits=True,
),
),
],
)
try:
# Create journey
api_response = api_instance.create_journey(app_id, create_journey_request)
pprint(api_response)
except onesignal.ApiException as e:
print("Exception when calling DefaultApi->create_journey: %s\n" % e)
print("Status Code: %s" % e.status)
print("Response Body: %s" % e.body)<?php
require_once(__DIR__ . '/vendor/autoload.php');
// Configure Bearer authorization: rest_api_key
$config = onesignal\client\Configuration::getDefaultConfiguration()
->setRestApiKeyToken('YOUR_REST_API_KEY')
->setOrganizationApiKeyToken('YOUR_ORGANIZATION_API_KEY');
$apiInstance = new onesignal\client\Api\DefaultApi(
// If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`.
// This is optional, `GuzzleHttp\Client` will be used as default.
new GuzzleHttp\Client(),
$config
);
$app_id = 'YOUR_APP_ID'; // string | Your OneSignal App ID in UUID v4 format.
$create_journey_request = new \onesignal\client\model\CreateJourneyRequest(); // \onesignal\client\model\CreateJourneyRequest
try {
$result = $apiInstance->createJourney($app_id, $create_journey_request);
print_r($result);
} catch (\onesignal\client\ApiException $e) {
echo 'Exception when calling DefaultApi->createJourney: ', $e->getMessage(), PHP_EOL;
echo 'Status Code: ', $e->getCode(), PHP_EOL;
// getErrorMessages() flattens any error-envelope shape to a string[];
// the raw body remains on getResponseBody().
echo 'Error Messages: ', implode(', ', $e->getErrorMessages()), PHP_EOL;
echo 'Response Body: ', $e->getResponseBody(), PHP_EOL;
} catch (\Exception $e) {
echo 'Exception when calling DefaultApi->createJourney: ', $e->getMessage(), PHP_EOL;
}package main
import (
"context"
"fmt"
"os"
"github.com/OneSignal/onesignal-go-api/v5"
)
func main() {
appId := "YOUR_APP_ID" // string | Your OneSignal App ID in UUID v4 format.
createJourneyRequest := *onesignal.NewCreateJourneyRequest("Name_example") // CreateJourneyRequest |
configuration := onesignal.NewConfiguration()
apiClient := onesignal.NewAPIClient(configuration)
restAuth := context.WithValue(context.Background(), onesignal.RestApiKey, "YOUR_REST_API_KEY") // App REST API key required for most endpoints
resp, r, err := apiClient.DefaultApi.CreateJourney(restAuth, appId).CreateJourneyRequest(createJourneyRequest).Execute()
if err != nil {
fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.CreateJourney``: %v\n", err)
fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
if apiErr, ok := err.(*onesignal.GenericOpenAPIError); ok {
// ErrorMessages() flattens any error-envelope shape to a []string;
// the raw body remains on Body().
fmt.Fprintf(os.Stderr, "Error Messages: %v\n", apiErr.ErrorMessages())
fmt.Fprintf(os.Stderr, "Response Body: %s\n", apiErr.Body())
}
}
// response from `CreateJourney`: Journey
fmt.Fprintf(os.Stdout, "Response from `DefaultApi.CreateJourney`: %v\n", resp)
}require 'onesignal'
# setup authorization
OneSignal.configure do |config|
# Configure Bearer authorization: rest_api_key
config.rest_api_key = 'YOUR_REST_API_KEY'
end
api_instance = OneSignal::DefaultApi.new
app_id = 'YOUR_APP_ID' # String | Your OneSignal App ID in UUID v4 format.
create_journey_request = OneSignal::CreateJourneyRequest.new({name: 'name_example'}) # CreateJourneyRequest |
begin
# Create journey
result = api_instance.create_journey(app_id, create_journey_request)
p result
rescue OneSignal::ApiError => e
puts "Error when calling DefaultApi->create_journey: #{e}"
puts "Status Code: #{e.code}"
# `e.error_messages` flattens any error-envelope shape to an Array<String>;
# the raw body remains on `e.response_body`.
puts "Error Messages: #{e.error_messages}"
puts "Response Body: #{e.response_body}"
end// Import classes:
import com.onesignal.client.ApiClient;
import com.onesignal.client.ApiException;
import com.onesignal.client.Configuration;
import com.onesignal.client.auth.*;
import com.onesignal.client.model.*;
import com.onesignal.client.api.DefaultApi;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("https://api.onesignal.com");
// Configure HTTP bearer authorization: rest_api_key
HttpBearerAuth rest_api_key = (HttpBearerAuth) defaultClient.getAuthentication("rest_api_key");
rest_api_key.setBearerToken("YOUR_REST_API_KEY");
DefaultApi apiInstance = new DefaultApi(defaultClient);
String appId = "YOUR_APP_ID"; // String | Your OneSignal App ID in UUID v4 format.
CreateJourneyRequest createJourneyRequest = new CreateJourneyRequest(); // CreateJourneyRequest |
try {
Journey result = apiInstance.createJourney(appId, createJourneyRequest);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling DefaultApi#createJourney");
System.err.println("Status code: " + e.getCode());
// getErrorMessages() flattens any error-envelope shape to a List<String>;
// the raw body remains on getResponseBody().
System.err.println("Error messages: " + e.getErrorMessages());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}using System;
using System.Collections.Generic;
using System.Diagnostics;
using OneSignalApi.Api;
using OneSignalApi.Client;
using OneSignalApi.Model;
namespace Example
{
public class CreateJourneyExample
{
public static void Main()
{
Configuration config = new Configuration();
config.BasePath = "https://api.onesignal.com";
// Configure Bearer token for authorization: rest_api_key
config.AccessToken = "YOUR_REST_API_KEY";
var apiInstance = new DefaultApi(config);
var appId = "YOUR_APP_ID"; // string | Your OneSignal App ID in UUID v4 format.
var createJourneyRequest = new CreateJourneyRequest(); // CreateJourneyRequest |
try
{
// Create journey
Journey result = apiInstance.CreateJourney(appId, createJourneyRequest);
Debug.WriteLine(result);
}
catch (ApiException e)
{
Debug.Print("Exception when calling DefaultApi.CreateJourney: " + e.Message );
Debug.Print("Status Code: "+ e.ErrorCode);
// e.ErrorMessages flattens any error-envelope shape to an IReadOnlyList<string>;
// the raw body remains on e.ErrorContent.
Debug.Print("Error Messages: " + string.Join(", ", e.ErrorMessages));
Debug.Print("Response Body: " + e.ErrorContent);
Debug.Print(e.StackTrace);
}
}
}
}use onesignal_rust_api::apis::configuration::Configuration;
use onesignal_rust_api::apis::default_api;
use onesignal_rust_api::models;
#[tokio::main]
async fn main() {
let mut configuration = Configuration::new();
configuration.rest_api_key_token = Some("YOUR_REST_API_KEY".to_string());
// Realistic values are pulled from the spec's `example:` fields where present.
let app_id: &str = "YOUR_APP_ID";
let create_journey_request: models::CreateJourneyRequest = todo!();
match default_api::create_journey(&configuration, app_id, create_journey_request).await {
Ok(resp) => println!("{:?}", resp),
Err(e @ onesignal_rust_api::apis::Error::ResponseError(_)) => {
// `e.error_messages()` flattens any error-envelope shape to a Vec<String>;
// the raw response remains on the ResponseError variant.
eprintln!("create_journey failed: {:?}", e.error_messages());
}
Err(e) => eprintln!("create_journey failed: {:?}", e),
}
}{
"id": "0a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9",
"app_id": "1a2b3c4d-5e6f-7081-92a3-b4c5d6e7f809",
"name": "Welcome series",
"description": "Onboard new users over their first week.",
"state": "draft",
"created_at": "2026-06-01T14:00:00Z",
"updated_at": "2026-06-01T14:00:00Z",
"started_at": null,
"archived_at": null,
"created_source": "public_api",
"audience": {
"kind": "segment",
"included_segment_ids": [
"3f7c1e90-0000-0000-0000-000000000001"
],
"excluded_segment_ids": [],
"future_additions_only": false
},
"early_exit": null,
"reentry_rules": null,
"schedule": null,
"nodes": [
{
"id": "11111111-0000-0000-0000-000000000001",
"kind": "send_push",
"template_id": "9a8b7c6d-0000-0000-0000-000000000001"
},
{
"id": "11111111-0000-0000-0000-000000000002",
"kind": "wait",
"duration_seconds": 86400
},
{
"id": "11111111-0000-0000-0000-000000000003",
"kind": "send_email",
"template_id": "9a8b7c6d-0000-0000-0000-000000000002"
}
],
"concurrency_key": "dcae4794fee16e450e448e37a6f8d0a5a7335755ff8cc76606e3d04b2f574e46"
}{
"errors": [
{
"code": "invalid-payload",
"title": "did not contain a required property of 'name'",
"meta": {
"attribute": "base",
"path": "name"
}
}
]
}{
"errors": [
{
"code": "journey-not-entitled",
"title": "Journeys are not enabled for this app",
"meta": {}
}
]
}Create journey
Create a new journey with an audience and a node graph. Journeys are always created in the draft state.
curl --request POST \
--url https://api.onesignal.com/apps/{app_id}/journeys \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"name": "Welcome series",
"description": "Onboard new users over their first week.",
"audience": {
"kind": "segment",
"included_segment_ids": [
"3f7c1e90-0000-0000-0000-000000000001"
],
"excluded_segment_ids": []
},
"nodes": [
{
"kind": "send_push",
"template_id": "9a8b7c6d-0000-0000-0000-000000000001"
},
{
"kind": "wait",
"duration_seconds": 86400
},
{
"kind": "send_email",
"template_id": "9a8b7c6d-0000-0000-0000-000000000002"
}
]
}
'import Onesignal from '@onesignal/node-onesignal';
const configuration = Onesignal.createConfiguration({
restApiKey: 'YOUR_REST_API_KEY',
});
const apiInstance = new Onesignal.DefaultApi(configuration);
// string | Your OneSignal App ID in UUID v4 format.
const appId: string = "YOUR_APP_ID";
// CreateJourneyRequest
const createJourneyRequest: Onesignal.CreateJourneyRequest = {
name: "name_example",
description: "description_example",
audience: {
kind: "segment",
included_segment_ids: [
"included_segment_ids_example",
],
excluded_segment_ids: [
"excluded_segment_ids_example",
],
future_additions_only: true,
name: "name_example",
attributes: [
[
{
key: "key_example",
operator: "equal",
value: "value_example",
},
],
],
},
early_exit: {
rules: {
on_segment: {
included_segment_ids: [
"included_segment_ids_example",
],
},
when_not_in_audience: true,
on_session: true,
on_event: {
name: "name_example",
},
},
tag_on_early_exit: {
"key": "key_example",
},
},
reentry_rules: {
duration_seconds: 600,
},
schedule: {
start_at: "start_at_example",
stop_at: "stop_at_example",
error: "error_example",
},
nodes: [
{
id: "id_example",
kind: "wait",
client_node_id: "client_node_id_example",
annotation: "annotation_example",
duration_seconds: 60,
relative_to: "schedule_in_timezone",
windows: [
{
start: null,
end: null,
day_of_week: 1,
},
],
time_zone: "time_zone_example",
use_user_time_zone: true,
template_id: "template_id_example",
iam_id: "iam_id_example",
user_ttl_seconds: 1,
webhook_id: "webhook_id_example",
assignments: {
"key": "key_example",
},
randomize_on_entry: true,
branches: [
{
id: "id_example",
condition: {
kind: "segment_membership",
included_segment_ids: [
"included_segment_ids_example",
],
excluded_segment_ids: [
"excluded_segment_ids_example",
],
action: "received",
sending_node_id: "sending_node_id_example",
client_node_id: "client_node_id_example",
name: "name_example",
attributes: [
[
{
key: "key_example",
operator: "equal",
value: "value_example",
},
],
],
entry_event_match_attributes: [
{},
],
},
weight: 3.14,
nodes: [
,
],
},
],
expiration: {
duration_seconds: 60,
exits: true,
},
},
],
};
try {
const response = await apiInstance.createJourney(appId, createJourneyRequest);
console.log(response);
} catch (e) {
if (e instanceof Onesignal.ApiException) {
// `e.errorMessages` flattens any error-envelope shape to a `string[]`;
// the raw parsed body remains on `e.body`.
console.error("createJourney failed: HTTP " + e.code, e.errorMessages);
} else {
throw e;
}
}import onesignal
from onesignal.api import default_api
from onesignal.models import *
from pprint import pprint
# See configuration.py for a list of all supported configuration parameters.
# Some of the OneSignal endpoints require ORGANIZATION_API_KEY token for authorization, while others require REST_API_KEY.
# We recommend adding both of them in the configuration page so that you will not need to figure it out yourself.
configuration = onesignal.Configuration(
rest_api_key = "YOUR_REST_API_KEY", # App REST API key required for most endpoints
organization_api_key = "YOUR_ORGANIZATION_API_KEY" # Organization key is only required for creating new apps and other top-level endpoints
)
# Enter a context with an instance of the API client
with onesignal.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = default_api.DefaultApi(api_client)
app_id = "YOUR_APP_ID" # Your OneSignal App ID in UUID v4 format.
create_journey_request = CreateJourneyRequest(
name="name_example",
description="description_example",
audience=JourneyAudience(
kind="segment",
included_segment_ids=[
"included_segment_ids_example",
],
excluded_segment_ids=[
"excluded_segment_ids_example",
],
future_additions_only=True,
name="name_example",
attributes=JourneyEventTriggerAttributes([
[
JourneyEventAttribute(
key="key_example",
operator="equal",
value="value_example",
),
],
]),
),
early_exit=JourneyEarlyExit(
rules=JourneyEarlyExitRules(
on_segment=JourneyEarlyExitRulesOnSegment(
included_segment_ids=[
"included_segment_ids_example",
],
),
when_not_in_audience=True,
on_session=True,
on_event=JourneyEarlyExitRulesOnEvent(
name="name_example",
),
),
tag_on_early_exit={
"key": "key_example",
},
),
reentry_rules=JourneyReentryRules(
duration_seconds=600,
),
schedule=JourneySchedule(
start_at="start_at_example",
stop_at="stop_at_example",
error="error_example",
),
nodes=[
JourneyNode(
id="id_example",
kind="wait",
client_node_id="client_node_id_example",
annotation="annotation_example",
duration_seconds=60,
relative_to="schedule_in_timezone",
windows=[
JourneyTimeWindow(
start=None,
end=None,
day_of_week=1,
),
],
time_zone="time_zone_example",
use_user_time_zone=True,
template_id="template_id_example",
iam_id="iam_id_example",
user_ttl_seconds=1,
webhook_id="webhook_id_example",
assignments={
"key": "key_example",
},
randomize_on_entry=True,
branches=[
JourneyBranch(
id="id_example",
condition=JourneyCondition(
kind="segment_membership",
included_segment_ids=[
"included_segment_ids_example",
],
excluded_segment_ids=[
"excluded_segment_ids_example",
],
action="received",
sending_node_id="sending_node_id_example",
client_node_id="client_node_id_example",
name="name_example",
attributes=JourneyEventTriggerAttributes([
[
JourneyEventAttribute(
key="key_example",
operator="equal",
value="value_example",
),
],
]),
entry_event_match_attributes=[
{},
],
),
weight=3.14,
nodes=[
JourneyNode(),
],
),
],
expiration=JourneyWaitUntilExpiration(
duration_seconds=60,
exits=True,
),
),
],
)
try:
# Create journey
api_response = api_instance.create_journey(app_id, create_journey_request)
pprint(api_response)
except onesignal.ApiException as e:
print("Exception when calling DefaultApi->create_journey: %s\n" % e)
print("Status Code: %s" % e.status)
print("Response Body: %s" % e.body)<?php
require_once(__DIR__ . '/vendor/autoload.php');
// Configure Bearer authorization: rest_api_key
$config = onesignal\client\Configuration::getDefaultConfiguration()
->setRestApiKeyToken('YOUR_REST_API_KEY')
->setOrganizationApiKeyToken('YOUR_ORGANIZATION_API_KEY');
$apiInstance = new onesignal\client\Api\DefaultApi(
// If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`.
// This is optional, `GuzzleHttp\Client` will be used as default.
new GuzzleHttp\Client(),
$config
);
$app_id = 'YOUR_APP_ID'; // string | Your OneSignal App ID in UUID v4 format.
$create_journey_request = new \onesignal\client\model\CreateJourneyRequest(); // \onesignal\client\model\CreateJourneyRequest
try {
$result = $apiInstance->createJourney($app_id, $create_journey_request);
print_r($result);
} catch (\onesignal\client\ApiException $e) {
echo 'Exception when calling DefaultApi->createJourney: ', $e->getMessage(), PHP_EOL;
echo 'Status Code: ', $e->getCode(), PHP_EOL;
// getErrorMessages() flattens any error-envelope shape to a string[];
// the raw body remains on getResponseBody().
echo 'Error Messages: ', implode(', ', $e->getErrorMessages()), PHP_EOL;
echo 'Response Body: ', $e->getResponseBody(), PHP_EOL;
} catch (\Exception $e) {
echo 'Exception when calling DefaultApi->createJourney: ', $e->getMessage(), PHP_EOL;
}package main
import (
"context"
"fmt"
"os"
"github.com/OneSignal/onesignal-go-api/v5"
)
func main() {
appId := "YOUR_APP_ID" // string | Your OneSignal App ID in UUID v4 format.
createJourneyRequest := *onesignal.NewCreateJourneyRequest("Name_example") // CreateJourneyRequest |
configuration := onesignal.NewConfiguration()
apiClient := onesignal.NewAPIClient(configuration)
restAuth := context.WithValue(context.Background(), onesignal.RestApiKey, "YOUR_REST_API_KEY") // App REST API key required for most endpoints
resp, r, err := apiClient.DefaultApi.CreateJourney(restAuth, appId).CreateJourneyRequest(createJourneyRequest).Execute()
if err != nil {
fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.CreateJourney``: %v\n", err)
fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
if apiErr, ok := err.(*onesignal.GenericOpenAPIError); ok {
// ErrorMessages() flattens any error-envelope shape to a []string;
// the raw body remains on Body().
fmt.Fprintf(os.Stderr, "Error Messages: %v\n", apiErr.ErrorMessages())
fmt.Fprintf(os.Stderr, "Response Body: %s\n", apiErr.Body())
}
}
// response from `CreateJourney`: Journey
fmt.Fprintf(os.Stdout, "Response from `DefaultApi.CreateJourney`: %v\n", resp)
}require 'onesignal'
# setup authorization
OneSignal.configure do |config|
# Configure Bearer authorization: rest_api_key
config.rest_api_key = 'YOUR_REST_API_KEY'
end
api_instance = OneSignal::DefaultApi.new
app_id = 'YOUR_APP_ID' # String | Your OneSignal App ID in UUID v4 format.
create_journey_request = OneSignal::CreateJourneyRequest.new({name: 'name_example'}) # CreateJourneyRequest |
begin
# Create journey
result = api_instance.create_journey(app_id, create_journey_request)
p result
rescue OneSignal::ApiError => e
puts "Error when calling DefaultApi->create_journey: #{e}"
puts "Status Code: #{e.code}"
# `e.error_messages` flattens any error-envelope shape to an Array<String>;
# the raw body remains on `e.response_body`.
puts "Error Messages: #{e.error_messages}"
puts "Response Body: #{e.response_body}"
end// Import classes:
import com.onesignal.client.ApiClient;
import com.onesignal.client.ApiException;
import com.onesignal.client.Configuration;
import com.onesignal.client.auth.*;
import com.onesignal.client.model.*;
import com.onesignal.client.api.DefaultApi;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("https://api.onesignal.com");
// Configure HTTP bearer authorization: rest_api_key
HttpBearerAuth rest_api_key = (HttpBearerAuth) defaultClient.getAuthentication("rest_api_key");
rest_api_key.setBearerToken("YOUR_REST_API_KEY");
DefaultApi apiInstance = new DefaultApi(defaultClient);
String appId = "YOUR_APP_ID"; // String | Your OneSignal App ID in UUID v4 format.
CreateJourneyRequest createJourneyRequest = new CreateJourneyRequest(); // CreateJourneyRequest |
try {
Journey result = apiInstance.createJourney(appId, createJourneyRequest);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling DefaultApi#createJourney");
System.err.println("Status code: " + e.getCode());
// getErrorMessages() flattens any error-envelope shape to a List<String>;
// the raw body remains on getResponseBody().
System.err.println("Error messages: " + e.getErrorMessages());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}using System;
using System.Collections.Generic;
using System.Diagnostics;
using OneSignalApi.Api;
using OneSignalApi.Client;
using OneSignalApi.Model;
namespace Example
{
public class CreateJourneyExample
{
public static void Main()
{
Configuration config = new Configuration();
config.BasePath = "https://api.onesignal.com";
// Configure Bearer token for authorization: rest_api_key
config.AccessToken = "YOUR_REST_API_KEY";
var apiInstance = new DefaultApi(config);
var appId = "YOUR_APP_ID"; // string | Your OneSignal App ID in UUID v4 format.
var createJourneyRequest = new CreateJourneyRequest(); // CreateJourneyRequest |
try
{
// Create journey
Journey result = apiInstance.CreateJourney(appId, createJourneyRequest);
Debug.WriteLine(result);
}
catch (ApiException e)
{
Debug.Print("Exception when calling DefaultApi.CreateJourney: " + e.Message );
Debug.Print("Status Code: "+ e.ErrorCode);
// e.ErrorMessages flattens any error-envelope shape to an IReadOnlyList<string>;
// the raw body remains on e.ErrorContent.
Debug.Print("Error Messages: " + string.Join(", ", e.ErrorMessages));
Debug.Print("Response Body: " + e.ErrorContent);
Debug.Print(e.StackTrace);
}
}
}
}use onesignal_rust_api::apis::configuration::Configuration;
use onesignal_rust_api::apis::default_api;
use onesignal_rust_api::models;
#[tokio::main]
async fn main() {
let mut configuration = Configuration::new();
configuration.rest_api_key_token = Some("YOUR_REST_API_KEY".to_string());
// Realistic values are pulled from the spec's `example:` fields where present.
let app_id: &str = "YOUR_APP_ID";
let create_journey_request: models::CreateJourneyRequest = todo!();
match default_api::create_journey(&configuration, app_id, create_journey_request).await {
Ok(resp) => println!("{:?}", resp),
Err(e @ onesignal_rust_api::apis::Error::ResponseError(_)) => {
// `e.error_messages()` flattens any error-envelope shape to a Vec<String>;
// the raw response remains on the ResponseError variant.
eprintln!("create_journey failed: {:?}", e.error_messages());
}
Err(e) => eprintln!("create_journey failed: {:?}", e),
}
}{
"id": "0a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9",
"app_id": "1a2b3c4d-5e6f-7081-92a3-b4c5d6e7f809",
"name": "Welcome series",
"description": "Onboard new users over their first week.",
"state": "draft",
"created_at": "2026-06-01T14:00:00Z",
"updated_at": "2026-06-01T14:00:00Z",
"started_at": null,
"archived_at": null,
"created_source": "public_api",
"audience": {
"kind": "segment",
"included_segment_ids": [
"3f7c1e90-0000-0000-0000-000000000001"
],
"excluded_segment_ids": [],
"future_additions_only": false
},
"early_exit": null,
"reentry_rules": null,
"schedule": null,
"nodes": [
{
"id": "11111111-0000-0000-0000-000000000001",
"kind": "send_push",
"template_id": "9a8b7c6d-0000-0000-0000-000000000001"
},
{
"id": "11111111-0000-0000-0000-000000000002",
"kind": "wait",
"duration_seconds": 86400
},
{
"id": "11111111-0000-0000-0000-000000000003",
"kind": "send_email",
"template_id": "9a8b7c6d-0000-0000-0000-000000000002"
}
],
"concurrency_key": "dcae4794fee16e450e448e37a6f8d0a5a7335755ff8cc76606e3d04b2f574e46"
}{
"errors": [
{
"code": "invalid-payload",
"title": "did not contain a required property of 'name'",
"meta": {
"attribute": "base",
"path": "name"
}
}
]
}{
"errors": [
{
"code": "journey-not-entitled",
"title": "Journeys are not enabled for this app",
"meta": {}
}
]
}Overview
Create a new Journey programmatically. A journey is defined by an entryaudience and an ordered list of nodes.
draft state. The request accepts only writable fields: sending a server-controlled field such as state or id returns a 400 validation error. Activate a journey with the Update journey API or from the OneSignal dashboard.id fields on nodes and branches are rejected on create with a 400 validation error. Use client_node_id if you need to reference a node from elsewhere in the same request.How to use this API
Authenticate with your App API Key. The authenticated key must have permission to create journeys. Onlyname is required. Sending an empty nodes array creates a journey with only its required defaults.
{
"name": "Welcome series",
"description": "Onboard new users over their first week.",
"audience": {
"kind": "segment",
"included_segment_ids": ["YOUR_SEGMENT_ID"],
"excluded_segment_ids": []
},
"nodes": [
{ "kind": "send_push", "template_id": "YOUR_TEMPLATE_ID" },
{ "kind": "wait", "duration_seconds": 86400 },
{ "kind": "send_email", "template_id": "YOUR_TEMPLATE_ID" }
]
}
Define the audience
Theaudience sets who enters the journey. It is either segment-based or event-triggered. Segments are referenced by UUID; every segment id (here, in early_exit, and in segment_membership branch conditions) must be a valid UUID that references an existing segment, or the request is rejected.
{
"audience": {
"kind": "segment",
"included_segment_ids": ["YOUR_SEGMENT_ID"],
"excluded_segment_ids": [],
"future_additions_only": false
}
}
{
"audience": {
"kind": "event_trigger",
"name": "purchase",
"attributes": [
[{ "key": "item_count", "operator": "greater_or_equal", "value": "5" }]
]
}
}
future_additions_only applies only to segment audiences and defaults to false. When true, only users who newly match the segment after the journey is activated can enter. Users already in the segment at activation never enter, even if they leave and rejoin later.
For event-triggered audiences, attributes is a list of condition groups. Send a single group, whose conditions are AND’d together; sending more than one group is rejected. Valid operators are equal, not_equal, less, less_or_equal, greater_or_equal, greater, is, is_not, exists, not_exists, before, and after. The value field is not required for exists and not_exists.
An event name is limited to 255 characters, and each attribute key to 255 and value to 1024.
equal, not_equal, less, less_or_equal, greater_or_equal, and greater compare numerically: value must be a number (sent as a string, e.g. "5" or "19.99"). A non-numeric value on these operators is rejected. Use is and is_not to compare non-numeric values such as a currency code or plan name.
Add nodes
nodes is an ordered list. Linear nodes run in sequence. Each node requires a kind, plus the fields for that kind.
[
{ "kind": "wait", "duration_seconds": 3600 },
{ "kind": "send_push", "template_id": "YOUR_TEMPLATE_ID" },
{ "kind": "send_iam", "iam_id": "YOUR_IAM_ID", "user_ttl_seconds": 86400 },
{ "kind": "send_webhook", "webhook_id": "YOUR_WEBHOOK_ID" },
{ "kind": "tag", "assignments": { "loyalty_tier": "gold", "churned": "" } }
]
{
"kind": "time_window",
"relative_to": "schedule_in_timezone",
"time_zone": "America/New_York",
"use_user_time_zone": false,
"windows": [
{ "start": { "hour": 9 }, "end": { "hour": 17 }, "day_of_week": 1 }
]
}
day_of_week (1–7, where 1 is Monday) is a sibling of start and end, not nested inside them. start and end hold only hour and minute. A window with no day_of_week applies to every day of the week. Each window must span at least 15 minutes.
A day-agnostic window is stored as seven per-day windows and returned in its original day-agnostic form, so a node read from a response can be sent back unchanged. One consequence: seven per-day windows that all share the same start and end are also returned as a single day-agnostic window.
windows apply only when relative_to is schedule_in_timezone. With relative_to: "last_active_time" a journey must not send windows; doing so is rejected. A last_active_time node is returned without a windows key, so a node read from a response can be sent back unchanged.
A send_push, send_email, or send_sms node’s template_id must reference an existing template of the matching channel (a push template for send_push, an email template for send_email, an SMS template for send_sms), or the request is rejected. Likewise a send_iam node’s iam_id and a send_webhook node’s webhook_id must reference existing resources. You may omit these ids while drafting, but a send node requires its id before the journey can go live.
A wait node’s duration_seconds must be between 60 seconds and 1 year (31556952 seconds). These bounds are enforced on create and on every update, in every state.
A tag node’s assignments keys are limited to 255 characters and values to 1024. An empty string value removes the tag. A node’s optional annotation is limited to 255.
Branching nodes
Branching nodes nest their sub-graphs inline throughbranches. After a branching node resolves, flow continues to the next sibling node.
{
"kind": "split_range",
"randomize_on_entry": false,
"branches": [
{ "weight": 50, "nodes": [{ "kind": "send_push", "template_id": "YOUR_TEMPLATE_ID" }] },
{ "weight": 50, "nodes": [] }
]
}
{
"kind": "yes_no",
"branches": [
{
"condition": {
"kind": "segment_membership",
"included_segment_ids": ["YOUR_SEGMENT_ID"],
"excluded_segment_ids": []
},
"nodes": [{ "kind": "send_email", "template_id": "YOUR_TEMPLATE_ID" }]
},
{ "nodes": [] }
]
}
{
"kind": "wait_until",
"branches": [
{
"condition": { "kind": "event_trigger", "name": "purchase", "attributes": [] },
"nodes": [{ "kind": "tag", "assignments": { "converted": "true" } }]
}
],
"expiration": { "duration_seconds": 604800, "exits": true }
}
split_rangetakes between 2 and 20 branches, and their weights must sum to 100.randomize_on_entrydefaults tofalse. Whentrue, the node assigns each user to a branch at random on entry.yes_norequires exactly two branches. The branch with aconditionis the “yes” branch; the branch without one is the “no” branch.wait_untiltakes between 1 and 10 condition branches. The optionalexpirationtimer exits the journey whenexitsistrue, or continues to convergence whenfalse. Itsduration_secondsfollows the same 60 second to 1 year bounds as awaitnode. Omitexpiration(or set it tonull) to wait indefinitely.
Branch conditions
yes_no and wait_until branches use a condition object selected by its kind:
kind | Fields |
|---|---|
segment_membership | included_segment_ids, excluded_segment_ids (segment UUIDs) |
on_notification_action | action, plus sending_node_id or client_node_id to reference the sending node |
event_trigger | name, attributes, optional entry_event_match_attributes |
on_notification_action condition branches on what a user did with a message sent earlier in the same journey. The sending node it references must be a message node (send_push, send_email, send_sms, send_iam, or send_webhook) that sits earlier in the flow than the branching node.
On create, the sending node has no server id yet. Give it a client_node_id that is unique within the journey, and send that same value on the condition. client_node_id on the condition is write-only: the API resolves it to the sending node’s id.
{
"nodes": [
{
"kind": "send_push",
"client_node_id": "welcome_push",
"template_id": "YOUR_TEMPLATE_ID"
},
{
"kind": "yes_no",
"branches": [
{
"condition": {
"kind": "on_notification_action",
"action": "clicked",
"client_node_id": "welcome_push"
},
"nodes": [{ "kind": "send_email", "template_id": "YOUR_TEMPLATE_ID" }]
},
{ "nodes": [] }
]
}
]
}
| Sending node | Supported actions |
|---|---|
send_push | received, clicked |
send_email | received, clicked, opened |
send_sms | received, opened |
send_iam | clicked, opened |
send_webhook node reports no user actions, so no action applies to it. An action outside this table is accepted by the API but never matches, so the branch is never taken.
An event_trigger condition’s attributes use the same list-of-lists shape and operators as an event-triggered audience. Its optional entry_event_match_attributes is a list of objects, each with two fields, used to match an incoming event against the event that entered the user into the journey:
{
"entry_event_match_attributes": [
{ "entry_event_key": "product_id", "incoming_event_key": "product_id" }
]
}
entry_event_key is the property on the entry event; incoming_event_key is the property on the incoming event compared against it. Both are required and must be non-blank.
Lifecycle and early exit
Optionally configureschedule, reentry_rules, and early_exit at the journey level.
{
"schedule": { "start_at": "2026-07-01T14:00:00Z", "stop_at": "2026-08-01T14:00:00Z" },
"reentry_rules": { "duration_seconds": 86400 },
"early_exit": {
"rules": {
"on_segment": { "included_segment_ids": ["YOUR_SEGMENT_ID"] },
"on_event": { "name": "exit_event" },
"on_session": true,
"when_not_in_audience": true
},
"tag_on_early_exit": { "has_exited": "true" }
}
}
scheduletimestamps must use UTC (Zor+00:00). Astart_atmust be at least 5 minutes in the future, and astop_atmust be in the future and later thanstart_at.reentry_rulessets how long a user must wait before re-entering.duration_secondsmust be at least 600 (10 minutes); a shorter value is rejected. Omitreentry_rulesor sendnullto disallow re-entry.early_exitremoves a user before the journey completes. At least one rule must be set underrules; anearly_exitthat configures no rule is rejected. Sendearly_exit: nullto remove early exit entirely.
Response
A successful request returns201 Created with the full journey in its draft state, including server-assigned id fields and a concurrency_key. Pass that concurrency_key unchanged on a later Update journey request to avoid overwriting a concurrent change. Activate the draft by sending state: "active" on that same endpoint.
The journey id and state, and node and branch id fields, are server-controlled. Sending any of them is rejected with 400 invalid-payload. A body app_id is ignored: the journey is always created under the app in the URL, and the response returns that app_id.
Error responses
| Status | Code | Description |
|---|---|---|
| 400 | invalid-payload | The request failed validation. This covers schema failures (for example, an unknown node kind, an unknown property, or a server-controlled field) and business-logic failures (for example, split_range branch weights that do not sum to 100). meta.path points to the offending field when applicable. |
| 403 | journey-not-entitled | Journeys are not enabled for this app. |
| 429 | Rate limit exceeded. Wait the number of seconds in the Retry-After header before retrying. See Rate limits. |
{ "errors": [{ "code", "title", "meta" }] }; for validation errors the failing field is in meta.attribute, with meta.path for the offending property. Branch on code and meta, not on title, whose wording can change between releases.Path Parameters
Your OneSignal App ID in UUID v4 format. See Keys & IDs.
Body
Journey name.
Optional journey description.
The journey entry audience. Either a segment-based or event-triggered audience.
- segment
- event_trigger
Show child attributes
Show child attributes
Conditions that remove a user from the journey before it completes. At least one rule must be set under rules; an early_exit that configures no rule is rejected. Send null to remove early exit entirely, or null for an individual rule to drop just that rule.
Show child attributes
Show child attributes
Controls whether and how soon a user can re-enter the journey. null means re-entry is not allowed.
Show child attributes
Show child attributes
Optional future start and/or stop time. null means no scheduled activation.
Show child attributes
Show child attributes
Ordered list of journey nodes. Server-assigned id fields are rejected on create with a 400 validation error.
A journey node. The kind field selects the shape. Branching nodes (split_range, yes_no, wait_until) nest their sub-graphs inline via branches[].nodes.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
- Option 9
Show child attributes
Show child attributes
Response
201
Full journey representation returned by the detail and create endpoints.
Journey UUID. Read-only.
UUID of the app the journey belongs to. Read-only.
Journey name, up to 300 characters.
Journey description, up to 1024 characters. Defaults to an empty string.
Journey state. Read-only. New journeys are created as draft. processing is a transient state while an activation is in progress, and archived is a journey that has been stopped. Change it through the state field on Update journey.
draft, scheduled, processing, active, archived ISO 8601 creation time. Read-only.
ISO 8601 last-update time. Read-only.
ISO 8601 time the journey was activated, or null. Read-only. May stay null briefly after you set state to active: activation is enqueued for processing, and started_at populates once the journey finishes processing and becomes active.
ISO 8601 time the journey was archived, or null. Read-only.
Origin of the journey, for example public_api or dashboard. Read-only.
The journey entry audience. Either a segment-based or event-triggered audience.
- segment
- event_trigger
Show child attributes
Show child attributes
Conditions that remove a user from the journey before it completes. At least one rule must be set under rules; an early_exit that configures no rule is rejected. Send null to remove early exit entirely, or null for an individual rule to drop just that rule.
Show child attributes
Show child attributes
Controls whether and how soon a user can re-enter the journey. null means re-entry is not allowed.
Show child attributes
Show child attributes
Optional future start and/or stop time. null means no scheduled activation.
Show child attributes
Show child attributes
Ordered list of journey nodes.
A journey node. The kind field selects the shape. Branching nodes (split_range, yes_no, wait_until) nest their sub-graphs inline via branches[].nodes.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
- Option 9
Show child attributes
Show child attributes
Opaque optimistic-concurrency token. Read-only. Pass it back on update to guard against overwriting a concurrent change (409 journey-stale). Send it back exactly as read from this response; do not construct or parse it.
Was this page helpful?