> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create journey

> Create a new journey with an audience and a node graph. Journeys are always created in the draft state.

<Info>
  **Beta.** The Journeys API is in beta. Endpoints and response fields can still change.
</Info>

## Overview

Create a new [Journey](/docs/en/journeys-overview) programmatically. A journey is defined by an entry `audience` and an ordered list of `nodes`.

<Note>
  Journeys are always created in the `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](/reference/update-journey) API or from the [OneSignal dashboard](/docs/en/managing-journeys).
</Note>

<Warning>
  Server-assigned `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.
</Warning>

***

## How to use this API

Authenticate with your [App API Key](/docs/en/keys-and-ids). The authenticated key must have permission to create journeys. Only `name` is required. Sending an empty `nodes` array creates a journey with only its required defaults.

```json theme={null}
{
  "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

The `audience` 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.

<CodeGroup>
  ```json Segment theme={null}
  {
    "audience": {
      "kind": "segment",
      "included_segment_ids": ["YOUR_SEGMENT_ID"],
      "excluded_segment_ids": [],
      "future_additions_only": false
    }
  }
  ```

  ```json Event-triggered theme={null}
  {
    "audience": {
      "kind": "event_trigger",
      "name": "purchase",
      "attributes": [
        [{ "key": "item_count", "operator": "greater_or_equal", "value": "5" }]
      ]
    }
  }
  ```
</CodeGroup>

`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.

<CodeGroup>
  ```json Linear nodes theme={null}
  [
    { "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": "" } }
  ]
  ```

  ```json time_window theme={null}
  {
    "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 }
    ]
  }
  ```
</CodeGroup>

Each window's `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 through `branches`. After a branching node resolves, flow continues to the next sibling node.

<CodeGroup>
  ```json split_range theme={null}
  {
    "kind": "split_range",
    "randomize_on_entry": false,
    "branches": [
      { "weight": 50, "nodes": [{ "kind": "send_push", "template_id": "YOUR_TEMPLATE_ID" }] },
      { "weight": 50, "nodes": [] }
    ]
  }
  ```

  ```json yes_no theme={null}
  {
    "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": [] }
    ]
  }
  ```

  ```json wait_until theme={null}
  {
    "kind": "wait_until",
    "branches": [
      {
        "condition": { "kind": "event_trigger", "name": "purchase", "attributes": [] },
        "nodes": [{ "kind": "tag", "assignments": { "converted": "true" } }]
      }
    ],
    "expiration": { "duration_seconds": 604800, "exits": true }
  }
  ```
</CodeGroup>

* `split_range` takes between 2 and 20 branches, and their weights must sum to 100. `randomize_on_entry` defaults to `false`. When `true`, the node assigns each user to a branch at random on entry.
* `yes_no` requires exactly two branches. The branch with a `condition` is the "yes" branch; the branch without one is the "no" branch.
* `wait_until` takes between 1 and 10 condition branches. The optional `expiration` timer exits the journey when `exits` is `true`, or continues to convergence when `false`. Its `duration_seconds` follows the same 60 second to 1 year bounds as a `wait` node. Omit `expiration` (or set it to `null`) 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`                      |

An `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`.

```json theme={null}
{
  "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": [] }
      ]
    }
  ]
}
```

Which actions are meaningful depends on the sending node's channel:

| Sending node | Supported actions               |
| ------------ | ------------------------------- |
| `send_push`  | `received`, `clicked`           |
| `send_email` | `received`, `clicked`, `opened` |
| `send_sms`   | `received`, `opened`            |
| `send_iam`   | `clicked`, `opened`             |

A `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:

```json theme={null}
{
  "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 configure `schedule`, `reentry_rules`, and `early_exit` at the journey level.

```json theme={null}
{
  "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" }
  }
}
```

* `schedule` timestamps must use UTC (`Z` or `+00:00`). A `start_at` must be at least 5 minutes in the future, and a `stop_at` must be in the future and later than `start_at`.
* `reentry_rules` sets how long a user must wait before re-entering. `duration_seconds` must be at least 600 (10 minutes); a shorter value is rejected. Omit `reentry_rules` or send `null` to disallow re-entry.
* `early_exit` removes a user before the journey completes. At least one rule must be set under `rules`; an `early_exit` that configures no rule is rejected. Send `early_exit: null` to remove early exit entirely.

## Response

A successful request returns `201 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](/reference/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](/reference/rate-limits).                                                                                                                                                                        |

Coded errors use the shape `{ "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.


## OpenAPI

````yaml POST /apps/{app_id}/journeys
openapi: 3.1.0
info:
  title: api.onesignal.com
  version: '11.6'
servers:
  - url: https://api.onesignal.com
security:
  - {}
paths:
  /apps/{app_id}/journeys:
    post:
      summary: Create journey
      description: >-
        Create a new journey. Journeys are always created in the `draft` state;
        sending a server-controlled field such as `state` or `id` returns a
        `400` validation error. Send an empty `nodes` array to create a journey
        with only its required defaults.
      operationId: create-journey
      parameters:
        - name: app_id
          in: path
          description: >-
            Your OneSignal App ID in UUID v4 format. See [Keys &
            IDs](/docs/en/keys-and-ids).
          schema:
            type: string
            default: YOUR_APP_ID
          required: true
        - name: Authorization
          in: header
          description: >-
            Your App API key with prefix `Key `. See [Keys &
            IDs](/docs/en/keys-and-ids).
          required: true
          schema:
            type: string
            default: Key YOUR_APP_API_KEY
        - name: Content-Type
          in: header
          required: true
          schema:
            type: string
            default: application/json; charset=utf-8
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  description: Journey name.
                  default: YOUR_JOURNEY_NAME
                description:
                  type:
                    - string
                    - 'null'
                  description: Optional journey description.
                audience:
                  $ref: '#/components/schemas/JourneyAudience'
                early_exit:
                  $ref: '#/components/schemas/JourneyEarlyExit'
                reentry_rules:
                  $ref: '#/components/schemas/JourneyReentryRules'
                schedule:
                  $ref: '#/components/schemas/JourneySchedule'
                nodes:
                  type: array
                  items:
                    $ref: '#/components/schemas/JourneyNode'
                  description: >-
                    Ordered list of journey nodes. Server-assigned `id` fields
                    are rejected on create with a `400` validation error.
            examples:
              Request:
                value:
                  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
      responses:
        '201':
          description: '201'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JourneyDetail'
              examples:
                Result:
                  value:
                    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
        '400':
          description: '400'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JourneyValidationErrorResponse'
              example:
                errors:
                  - code: invalid-payload
                    title: did not contain a required property of 'name'
                    meta:
                      attribute: base
                      path: name
        '403':
          description: '403'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JourneyCodedErrorResponse'
              example:
                errors:
                  - code: journey-not-entitled
                    title: Journeys are not enabled for this app
                    meta: {}
        '429':
          description: '429'
          headers:
            Retry-After:
              description: >-
                Number of seconds to wait before retrying the request. Always
                emitted on 429 responses.
              schema:
                type: integer
                minimum: 0
components:
  schemas:
    JourneyAudience:
      oneOf:
        - type: object
          title: segment
          required:
            - kind
          properties:
            kind:
              type: string
              const: segment
            included_segment_ids:
              type: array
              items:
                type: string
              description: Segment UUIDs whose users enter the journey.
            excluded_segment_ids:
              type: array
              items:
                type: string
              description: Segment UUIDs whose users are excluded.
            future_additions_only:
              type: boolean
              description: >-
                When true, only users who newly match the segment after
                activation enter the journey. Defaults to false.
        - type: object
          title: event_trigger
          required:
            - kind
          properties:
            kind:
              type: string
              const: event_trigger
            name:
              type: string
              description: Event name that triggers entry, up to 255 characters.
            attributes:
              $ref: '#/components/schemas/JourneyEventTriggerAttributes'
      description: >-
        The journey entry audience. Either a segment-based or event-triggered
        audience.
    JourneyEarlyExit:
      type:
        - object
        - 'null'
      description: >-
        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.
      properties:
        rules:
          type: object
          properties:
            on_segment:
              type:
                - object
                - 'null'
              properties:
                included_segment_ids:
                  type: array
                  items:
                    type: string
                  description: Exit when the user enters any of these segments.
            when_not_in_audience:
              type:
                - boolean
                - 'null'
              description: >-
                Exit when the user no longer matches the journey audience.
                Defaults to false.
            on_session:
              type:
                - boolean
                - 'null'
              description: Exit on a new session start. Defaults to false.
            on_event:
              type:
                - object
                - 'null'
              required:
                - name
              properties:
                name:
                  type: string
                  description: Exit when this event occurs. Up to 255 characters.
        tag_on_early_exit:
          type: object
          additionalProperties:
            type: string
          description: Tag key-value pairs applied when a user exits early.
    JourneyReentryRules:
      type:
        - object
        - 'null'
      description: >-
        Controls whether and how soon a user can re-enter the journey. `null`
        means re-entry is not allowed.
      properties:
        duration_seconds:
          type: integer
          minimum: 600
          description: >-
            Minimum seconds before a user can re-enter. Must be at least `600`
            (10 minutes).
    JourneySchedule:
      type:
        - object
        - 'null'
      description: >-
        Optional future start and/or stop time. `null` means no scheduled
        activation.
      properties:
        start_at:
          type:
            - string
            - 'null'
          description: >-
            ISO 8601 start time. Use UTC (`Z` or `+00:00`). Must be at least 5
            minutes in the future.
        stop_at:
          type:
            - string
            - 'null'
          description: >-
            ISO 8601 stop time. Use UTC (`Z` or `+00:00`). Must be in the future
            and later than `start_at`.
        error:
          type:
            - string
            - 'null'
          description: Read-only. Present when a scheduling error occurred.
    JourneyNode:
      oneOf:
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              const: wait
              description: Holds the user for a fixed duration before continuing.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            duration_seconds:
              type: integer
              description: >-
                Seconds to hold the user. Minimum `60`, maximum `31556952` (1
                year).
              minimum: 60
              maximum: 31556952
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              const: time_window
              description: Holds the user until the next configured time window opens.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            relative_to:
              type: string
              enum:
                - schedule_in_timezone
                - last_active_time
              description: >-
                `schedule_in_timezone` uses the configured windows;
                `last_active_time` holds relative to the user's last active
                time.
            windows:
              type: array
              items:
                $ref: '#/components/schemas/JourneyTimeWindow'
              description: >-
                One or more time windows. A window with no `day_of_week` applies
                to every day, and is returned in that same day-agnostic form.
                Required when `relative_to` is `schedule_in_timezone`; must be
                omitted when it is `last_active_time`, and is absent from
                responses for those nodes.
            time_zone:
              type: string
              description: >-
                IANA timezone identifier used when the user's timezone is
                unavailable.
            use_user_time_zone:
              type: boolean
              description: When true, uses the user's timezone if available.
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              enum:
                - send_push
                - send_email
                - send_sms
              description: Sends a message on the given channel using a template.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            template_id:
              type: string
              description: UUID of the template to send.
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              const: send_iam
              description: Sends an in-app message.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            iam_id:
              type: string
              description: UUID of the in-app message to send.
            user_ttl_seconds:
              type: integer
              minimum: 1
              description: Optional time-to-live for the in-app message, in seconds.
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              const: send_webhook
              description: Sends a webhook.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            webhook_id:
              type: string
              description: UUID of the webhook to send.
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              const: tag
              description: Assigns key-value tags to the user.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            assignments:
              type: object
              additionalProperties:
                type: string
              description: >-
                Tag key-value pairs to assign. An empty string value removes the
                tag. Keys are limited to 255 characters and values to 1024.
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              const: split_range
              description: >-
                Routes users into weighted branches that converge to the next
                sibling node.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            randomize_on_entry:
              type: boolean
              description: >-
                When true, assigns each user to a branch at random on entry.
                Defaults to false.
            branches:
              type: array
              items:
                $ref: '#/components/schemas/JourneyBranch'
              description: >-
                Weighted branches. Between 2 and 20. Weights must sum to 100.
                Order determines display order.
              minItems: 2
              maxItems: 20
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              const: yes_no
              description: Routes users into a yes or no branch based on a condition.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            branches:
              type: array
              minItems: 2
              maxItems: 2
              items:
                $ref: '#/components/schemas/JourneyBranch'
              description: >-
                Exactly two branches. The branch with a `condition` is the "yes"
                branch; the branch without one is the "no" branch.
        - type: object
          required:
            - kind
          properties:
            id:
              type: string
              description: >-
                Server-assigned node UUID. Read-only. Returned on reads; sending
                it on create is rejected with a `400` validation error.
            kind:
              type: string
              const: wait_until
              description: >-
                Holds the user until any branch condition is met, or an optional
                expiration timer fires.
            client_node_id:
              type: string
              description: >-
                Optional client-assigned identifier, unique within the journey.
                Use it to reference this node from elsewhere in the same request
                (for example as `client_node_id` on an `on_notification_action`
                condition). Persisted and returned on reads.
            annotation:
              type: string
              description: >-
                Optional free-text label, up to 255 characters. Stored and
                returned as-is with no effect on journey behavior.
            branches:
              type: array
              items:
                $ref: '#/components/schemas/JourneyBranch'
              description: >-
                Condition branches. At least one required, at most 10. Order
                determines priority.
            expiration:
              type:
                - object
                - 'null'
              properties:
                duration_seconds:
                  type: integer
                  minimum: 60
                  description: >-
                    Seconds to wait before the timer fires. Minimum `60`,
                    maximum `31556952` (1 year).
                  maximum: 31556952
                exits:
                  type: boolean
                  description: >-
                    When true, the user exits the journey when the timer fires;
                    when false, the user continues to convergence.
              description: Optional expiration timer. `null` waits indefinitely.
      description: >-
        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`.
    JourneyDetail:
      type: object
      description: Full journey representation returned by the detail and create endpoints.
      properties:
        id:
          type: string
          description: Journey UUID. Read-only.
        app_id:
          type: string
          description: UUID of the app the journey belongs to. Read-only.
        name:
          type: string
          description: Journey name, up to 300 characters.
        description:
          type:
            - string
            - 'null'
          description: >-
            Journey description, up to 1024 characters. Defaults to an empty
            string.
        state:
          type: string
          enum:
            - draft
            - scheduled
            - processing
            - active
            - archived
          description: >-
            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](/reference/update-journey).
        created_at:
          type: string
          description: ISO 8601 creation time. Read-only.
        updated_at:
          type: string
          description: ISO 8601 last-update time. Read-only.
        started_at:
          type:
            - string
            - 'null'
          description: >-
            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:
          type:
            - string
            - 'null'
          description: ISO 8601 time the journey was archived, or `null`. Read-only.
        created_source:
          type:
            - string
            - 'null'
          description: >-
            Origin of the journey, for example `public_api` or `dashboard`.
            Read-only.
        audience:
          $ref: '#/components/schemas/JourneyAudience'
        early_exit:
          $ref: '#/components/schemas/JourneyEarlyExit'
        reentry_rules:
          $ref: '#/components/schemas/JourneyReentryRules'
        schedule:
          $ref: '#/components/schemas/JourneySchedule'
        nodes:
          type: array
          items:
            $ref: '#/components/schemas/JourneyNode'
          description: Ordered list of journey nodes.
        concurrency_key:
          type: string
          description: >-
            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.
    JourneyValidationErrorResponse:
      type: object
      description: >-
        Validation error response. Uses the same `code`/`title`/`meta` shape as
        every other error; the failing field and any positional detail travel in
        `meta`.
      properties:
        errors:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                description: >-
                  Stable, kebab-case error identifier. Always `invalid-payload`
                  for validation failures.
              title:
                type: string
                description: Human-readable message. Wording may change between releases.
              meta:
                type: object
                description: >-
                  Structured context. Always includes `attribute` (the field, or
                  `base` for request-level errors); may also include `path`,
                  `node_id`, or `client_node_id`.
    JourneyCodedErrorResponse:
      type: object
      description: Error response with a stable machine-readable `code`.
      properties:
        errors:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                description: >-
                  Stable, kebab-case error identifier. Does not change once
                  shipped.
              title:
                type: string
                description: Human-readable message. Wording may change between releases.
              meta:
                type: object
                description: Optional structured context. Shape varies by error.
    JourneyEventTriggerAttributes:
      type: array
      description: >-
        Event attribute matchers, as a list of condition groups. Send a single
        group whose conditions are AND'd together. More than one group is
        rejected.
      items:
        type: array
        items:
          type: object
          required:
            - key
            - operator
          properties:
            key:
              type: string
              description: Event attribute key.
            operator:
              type: string
              enum:
                - equal
                - not_equal
                - less
                - less_or_equal
                - greater_or_equal
                - greater
                - is
                - is_not
                - exists
                - not_exists
                - before
                - after
              description: Comparison operator.
            value:
              type: string
              description: >-
                Value to compare against. Not required for `exists` and
                `not_exists`.
    JourneyTimeWindow:
      type: object
      properties:
        start:
          allOf:
            - $ref: '#/components/schemas/JourneyTimePoint'
          description: When the window opens.
        end:
          allOf:
            - $ref: '#/components/schemas/JourneyTimePoint'
          description: When the window closes.
        day_of_week:
          type: integer
          minimum: 1
          maximum: 7
          description: Day of week, 1 = Monday. Omit to apply the window to every day.
      description: A wall-clock window. Each window must span at least 15 minutes.
    JourneyBranch:
      type: object
      properties:
        id:
          type: string
          description: Server-assigned branch identifier. Read-only.
        condition:
          $ref: '#/components/schemas/JourneyCondition'
        weight:
          type: number
          description: >-
            Branch weight for `split_range` nodes. Weights across a node's
            branches must sum to 100.
        nodes:
          type: array
          items:
            $ref: '#/components/schemas/JourneyNode'
          description: >-
            Nodes run when this branch is taken, before flow converges to the
            next sibling node.
    JourneyTimePoint:
      type: object
      properties:
        hour:
          type: integer
          minimum: 0
          maximum: 23
          description: Hour of day, 0-23.
        minute:
          type: integer
          minimum: 0
          maximum: 59
          description: Minute of hour, 0-59. Defaults to 0.
    JourneyCondition:
      oneOf:
        - type: object
          title: segment_membership
          required:
            - kind
          properties:
            kind:
              type: string
              const: segment_membership
            included_segment_ids:
              type: array
              items:
                type: string
              description: Segment UUIDs the user must belong to.
            excluded_segment_ids:
              type: array
              items:
                type: string
              description: Segment UUIDs the user must not belong to.
        - type: object
          title: on_notification_action
          required:
            - kind
          properties:
            kind:
              type: string
              const: on_notification_action
            action:
              type: string
              enum:
                - received
                - clicked
                - opened
              description: >-
                The notification action to branch on. Which actions apply
                depends on the sending node's channel.
            sending_node_id:
              type: string
              description: >-
                `id` of the sending node this action refers to. Returned on
                reads; accepted on write.
            client_node_id:
              type: string
              description: >-
                Write-only alternative to `sending_node_id`. References the
                sending node by its `client_node_id`, which is resolved to that
                node's `id`.
        - type: object
          title: event_trigger
          required:
            - kind
          properties:
            kind:
              type: string
              const: event_trigger
            name:
              type: string
              description: Event name, up to 255 characters.
            attributes:
              $ref: '#/components/schemas/JourneyEventTriggerAttributes'
            entry_event_match_attributes:
              type:
                - array
                - 'null'
              items:
                type: object
              description: >-
                Match incoming event properties against the journey's entry
                event. Only valid on event-triggered journeys.
      description: A branch condition. The `kind` field selects the shape.

````