Skip to main content
POST
Duplicate journey
Beta. The Journeys API is in beta. Endpoints and response fields can still change.

Overview

Copy the Journey named in the path. The copy is a new journey in the draft state. The source does not change.
The copy is always a draft, whatever state the source is in. If you duplicate an active or archived journey, the copy has started_at and archived_at set to null. To activate the copy, use the Update journey API or the OneSignal dashboard.

How to use this API

Authenticate with your App API Key. The key must have permission to create journeys. To find the id of the source journey, use the View journeys API. You can also open the journey in the dashboard and read the id from the URL.
The body is optional. If you send no body, the copy matches the source. The copy then takes a derived name, which is the name of the source plus a suffix.

What the copy inherits

The copy carries the description, audience, nodes, early_exit, and reentry_rules of the source.
  • name: the copy takes the name of the source plus (Copy). If the result is longer than the 300 character limit, the source part is truncated to fit. If you duplicate a copy, the suffix is added again rather than counted.
  • nodes: nodes and branches get new id values from the server. A client_node_id is a value that you assign, so the copy keeps it unchanged. An on_notification_action condition points at the matching node in the copy.
  • schedule: the copy does not inherit it, because a copied start_at is almost always in the past. To schedule the copy, send a schedule under overrides.
  • state is draft, started_at and archived_at are null, and created_source is public_api. The copy gets its own concurrency_key.
Stats do not carry over. The copy starts with no entries, and the source keeps its own journey stats.

Apply overrides

overrides holds a journey document that is applied over the copy. It uses JSON Merge Patch (RFC 7396), which merges one document into another. overrides accepts the same writable fields as Create journey, and none of them are required. Use it to create the copy in its final state, instead of creating the copy and then patching it.
Merge patch works field by field:
  • An object merges into the copied object key by key. The early_exit above adds a rule and leaves the other rules of the source in place.
  • null clears the copied value. The "description": null above gives the copy no description.
  • An array replaces the copied array as a unit. A nodes array replaces the whole graph of the source and does not merge into it. Send the complete graph that you want.
  • If an audience override changes kind, the copy drops the fields of the previous kind. It does not keep them beside the new fields.
Do not send server-controlled fields. Sending them is rejected with a 400 validation error, exactly as on Create journey. This covers the journey id and state, the lifecycle timestamps, and the id fields on nodes and branches.
A nodes override replaces the graph, so an id inside it addresses nothing. To reference a node from elsewhere in the same request, use client_node_id. Only overrides is read from the body. A journey field sent at the top level is ignored rather than rejected. For example, {"name": "Renamed"} leaves the copy with the derived name.

Response

A successful request returns 201 Created and the full copy in the draft state. The response contains the id fields from the server and the concurrency_key. On a later Update journey request, pass that concurrency_key unchanged. It stops your request from overwriting a concurrent change.

Error responses

Entitlements are measured against the copy, not the source. An app cannot use this endpoint to create a journey that it has no entitlement to create. Coded errors use the shape { "errors": [{ "code", "title", "meta" }] }. Branch on code and meta, not on title, whose wording comes from the schema validator and can change between releases. A schema failure reports base in meta.attribute and a JSON Pointer (RFC 6901) in meta.path. The pointer names the object that holds the offending property, not the property itself, and the same pointer appears in title. Both are relative to the overrides document rather than to the request body. A rejected state at the top of overrides therefore reports #/, and meta.path is omitted because the pointer is the root. A business-logic failure on the copy names the field in meta.attribute instead.

Headers

Authorization
string
default:Key YOUR_APP_API_KEY
required

Your App API key with prefix Key. See Keys & IDs.

Content-Type
string
default:application/json; charset=utf-8
required

Path Parameters

app_id
string
default:YOUR_APP_ID
required

Your OneSignal App ID in UUID v4 format. See Keys & IDs.

id
string
default:YOUR_JOURNEY_ID
required

UUID of the journey to copy.

Body

application/json
overrides
object

Journey fields to apply to the copy. Accepts the same writable fields as Create journey, and none of them are required. Fields sent outside overrides are ignored.

Response

201

Full journey representation returned by the detail and create endpoints.

id
string

Journey UUID. Read-only.

app_id
string

UUID of the app the journey belongs to. Read-only.

name
string

Journey name, up to 300 characters.

description
string | null

Journey description, up to 1024 characters. Defaults to an empty string.

state
enum<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.

Available options:
draft,
scheduled,
processing,
active,
archived
created_at
string

ISO 8601 creation time. Read-only.

updated_at
string

ISO 8601 last-update time. Read-only.

started_at
string | null

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.

archived_at
string | null

ISO 8601 time the journey was archived, or null. Read-only.

created_source
string | null

Origin of the journey, for example public_api or dashboard. Read-only.

audience
segment · object

The journey entry audience. Either a segment-based or event-triggered audience.

early_exit
object | null

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.

reentry_rules
object | null

Controls whether and how soon a user can re-enter the journey. null means re-entry is not allowed.

schedule
object | null

Optional future start and/or stop time. null means no scheduled activation.

nodes
object[]

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.

concurrency_key
string

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.