Update journey
Apply a partial update to a journey with JSON Merge Patch, and activate a draft journey by transitioning its state.
Overview
Update an existing Journey programmatically. The request is a JSON Merge Patch (RFC 7396): send only the fields you want to change, and omitted fields are left unchanged. Sendstate: "active" to activate a draft journey. Editing rules tighten once a journey is active, because it carries in-flight users. See Editing an active journey.
To change a single node without re-sending the whole graph, use Update journey node.
How to use this API
Authenticate with your App API Key. The authenticated key must have permission to update journeys. Find a journey’sid from the View journeys API or in the dashboard URL.
Fetch the journey first with View journey, then send only the fields you are changing. A minimal rename touches only one field:
Merge patch behavior
The request body is merged onto the journey’s current representation:- A field you send replaces the current value. Omitted fields are untouched.
- A
nullvalue clears a nullable field.description,schedule,early_exit, andreentry_rulesacceptnullto reset them to their defaults. - An individual early-exit rule accepts
null. Sendearly_exit: { "rules": { "on_session": null } }to drop one rule while keeping the others. Clearing the last remaining rule is rejected, since anearly_exitwith no rule configures nothing; sendearly_exit: nullto remove early exit entirely. - Arrays are replaced as a unit.
nodes, a node’sbranches, andwindowsare not merged element-wise. Send the full array you want. - Changing the audience
kindswaps the whole object. Theaudienceis a tagged union identified by itskind. Changing thekind(segment↔event_trigger) is only allowed while the journey is a draft or scheduled; once it is live the audience type is frozen (see Editing an active journey). When you do change it, send only the new variant’s fields; the previous variant’s fields are dropped rather than merged, so you do not need tonullthem.
audience from a segment to an event trigger by sending the new variant alone; the old included_segment_ids and excluded_segment_ids are dropped:
Preserve node ids
Becausenodes is an array, a request that includes it replaces the whole graph. A node sent without an id is treated as a new node, so omitting the ids of nodes you meant to keep discards those nodes and recreates them under new ids. Any users in flight on them are lost. Node fields follow the same schema and validation as Create journey.
Fetch the journey with View journey first, then send back every node you want to keep, each with the id the server assigned it:
branches array works the same way. Echo each branch’s id to keep it, and note that an active journey’s branches cannot be added or removed at all.
To change one node without re-sending the graph, use Update journey node instead. It addresses a single node by its id and leaves every other node untouched.
Optimistic concurrency
To avoid overwriting a concurrent change, pass theconcurrency_key returned by a prior View journey fetch. If the journey has changed since that fetch, the request is rejected with 409 journey-stale and nothing is written. Omit concurrency_key to skip the check.
concurrency_key as an opaque token: read it from the journey you are editing and send it back unchanged. Do not construct, parse, or compare it yourself.Journey states
A journey reports one of five states.draft, scheduled, active, and archived are settable through this endpoint; processing is reported by the server only.
Activate a journey
Setstate to transition a journey through its lifecycle. The common case is activating a draft:
- Only
draftjourneys can transition toscheduled, and it requires aschedulewith astart_at. - A journey can return to
draftonly fromscheduledorprocessing. There is no way to move a running journey back todraft. - Send
state: "archived"to stop a running journey. Archiving halts all user progress and is permanent: an archived journey can still be read, but it cannot resume sending, and later writes return422 journey-archived. Adraftjourney cannot be archived. scheduletimestamps must use UTC (Zor+00:00).
state to active starts activation, it does not complete it. The request returns once the activation work is enqueued, so a 200 does not mean the journey is running yet. Until activation finishes, the journey reports state: "processing" and its started_at stays null. Poll View journey until state reads active before you treat the journey as live.Editing an active journey
An active journey carries in-flight users, so its structure is largely frozen. The API rejects edits that would strand users:- Non-structural nodes (such as
send_pushorwait) can be removed. Users already in flight on a removed node continue forward through the rest of the journey. - Structural nodes (
split_range,yes_no,wait_until) cannot be removed. A new branching node can be added. - An existing branching node’s set of branches cannot change.
- The schedule
start_atis frozen once the journey has leftdraftorscheduled. Change it while the journey is still a draft or scheduled. - The schedule
stop_atstays editable in every state, including while active, so you can extend or shorten a running journey’s end date. It must be in the future and later thanstart_at. - A node’s
client_node_idis immutable once the journey is live; change it while the journey is stilldraftorscheduled. - The audience type is immutable once the journey is live. That covers both switching between a
segmentand anevent_triggeraudience and togglingfuture_additions_onlyon a segment audience, since a future-only audience counts as its own type. - You can still retarget within the same type: a segment audience’s segments, or an event-trigger audience’s event name and attributes. The one exception is a future-only segment audience, whose segment set is frozen once live.
400 with a field-level error describing the conflict.
Response
A successful request returns200 OK with the full updated journey, including server-assigned id fields and a concurrency_key. Pass that concurrency_key unchanged on a later update to avoid overwriting a concurrent change.
Error responses
{ "errors": [{ "code", "title", "meta" }] }; for validation errors the failing field is in meta.attribute, with meta.path for the offending property.Path Parameters
Your OneSignal App ID in UUID v4 format. See Keys & IDs.
UUID of the journey to update.
Body
Journey name.
Journey description. Send null to clear it.
The journey entry audience. Either a segment-based or event-triggered audience.
- segment
- event_trigger
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.
Controls whether and how soon a user can re-enter the journey. null means re-entry is not allowed.
Optional future start and/or stop time. null means no scheduled activation.
Full ordered list of nodes, which replaces the existing graph wholesale. Preserve each node's server-assigned id from a prior fetch to keep in-flight users on that node; omit id to add a new node.
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
Target state. Set active to activate a draft journey, or scheduled together with a future schedule.start_at to activate it later. Set archived to stop a running journey; archiving is permanent, and later writes return 422 journey-archived. Only scheduled and processing journeys can return to draft.
draft, scheduled, active, archived Optional optimistic-concurrency token. Pass the concurrency_key from a prior fetch to reject the update with 409 if the journey changed in the meantime. Omit to skip the check.
Response
200
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
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.
Controls whether and how soon a user can re-enter the journey. null means re-entry is not allowed.
Optional future start and/or stop time. null means no scheduled activation.
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
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.