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

# View journey stats

> Retrieve performance stats for a single journey, including journey-level counts, per-node counts, per-branch counts, and channel delivery stats.

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

## Overview

Retrieve performance stats for a single [Journey](/docs/en/journeys-overview) by its UUID. The response has four parts:

* Journey-level counts: `started`, `completed`, and `exited_early`.
* A `nodes` map of per-node counts, keyed by node `id`.
* A `branches` map of per-branch counts, keyed by branch `id`.
* A `message_stats` object on each message-sending node with that channel's delivery stats.

These are the same numbers shown in the [journey report](/docs/en/journeys-analytics) in the dashboard.

<Note>
  The response is stats-only and carries no definition detail. Fetch the journey with [View journey](/reference/view-journey) and join the two by `id` to pair each count with the node or branch it describes.
</Note>

***

## How to use this API

Authenticate with your [App API Key](/docs/en/keys-and-ids). The authenticated key must have permission to view journeys. Find a journey's `id` from the [View journeys](/reference/view-journeys) API or in the dashboard URL when viewing the journey.

```http theme={null}
GET /apps/{app_id}/journeys/{id}/stats
```

Stats are all-time totals. The endpoint takes no query parameters, so there is no date range or granularity option.

A successful request returns `200 OK`. Channel keys live under `message_stats.totals`, not on `message_stats` itself:

```json theme={null}
{
  "id": "0a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9",
  "started": 1000,
  "completed": 820,
  "exited_early": 60,
  "nodes": {
    "11111111-0000-0000-0000-000000000001": {
      "kind": "send_push",
      "waiting": 0,
      "completed": 980,
      "exited_early": 20,
      "message_stats": {
        "totals": {
          "sent": 1000,
          "delivered": 940,
          "clicked": 210,
          "failed": 45
        }
      }
    },
    "11111111-0000-0000-0000-000000000002": {
      "kind": "wait",
      "waiting": 120,
      "completed": 820,
      "exited_early": 40
    }
  },
  "branches": {}
}
```

### Journey-level counts

| Field          | Description                                            |
| -------------- | ------------------------------------------------------ |
| `id`           | UUID of the journey these stats belong to.             |
| `started`      | Users who entered the journey.                         |
| `completed`    | Users who reached the end of the journey normally.     |
| `exited_early` | Users who left the journey through an early exit rule. |

A journey in `draft` returns the endpoint's normal shape with zeroed counts.

### Node stats

`nodes` is an object keyed by node `id`, not an array. Every node in the graph is included, at any nesting depth, so nodes nested inside a branching node's `branches` appear as top-level entries in this map alongside their parent.

| Field           | Description                                                                                                                                  |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `kind`          | The node's kind, repeated here so stats can be read without joining against the journey definition.                                          |
| `waiting`       | Users currently held at this node. This is users who entered the node minus those who advanced past it minus those who exited early from it. |
| `completed`     | Users who advanced past this node normally.                                                                                                  |
| `exited_early`  | Users who left the journey from this node through an early exit rule.                                                                        |
| `message_stats` | Channel delivery stats. Present only on message-sending nodes.                                                                               |

### Branch stats

`branches` is an object keyed by branch `id`, covering the branches of every `split_range`, `yes_no`, and `wait_until` node. Each entry has a single field, `completed`, counting the users who took that branch. The map is empty for a journey with no branching nodes.

### Message stats by channel

`message_stats` is present on `send_push`, `send_email`, `send_sms`, `send_iam`, and `send_webhook` nodes only. Its `totals` keys depend on the channel. The **Dashboard term** column below is the label the same metric carries in the dashboard, so you can look it up in the [metrics glossary](/docs/en/analytics-metrics-glossary).

<Tabs>
  <Tab title="Push">
    | Field                 | Dashboard term    | Description                                                                                     |
    | --------------------- | ----------------- | ----------------------------------------------------------------------------------------------- |
    | `sent`                | Sent              | Push messages sent.                                                                             |
    | `delivered`           | Delivered         | Messages accepted by the platform delivery service.                                             |
    | `confirmed_delivered` | Confirmed Receipt | Deliveries confirmed by the device. Requires [confirmed delivery](/docs/en/confirmed-delivery). |
    | `clicked`             | Clicked           | Message clicks.                                                                                 |
    | `failed`              | Failed            | Deliveries that errored.                                                                        |
    | `unsubscribed`        | Unsubscribed      | Subscriptions that became unsubscribed, i.e. invalid or revoked push tokens.                    |
    | `frequency_capped`    | Frequency Capped  | Sends suppressed by [frequency capping](/docs/en/frequency-capping).                            |

    The [View message](/reference/view-message) API names these two fields differently for backward compatibility: its `failed` means unsubscribed and its `errored` means delivery errors. This endpoint uses the plain names instead, so `failed` here is the dashboard's Failed.
  </Tab>

  <Tab title="Email">
    | Field          | Dashboard term   | Description                                                        |
    | -------------- | ---------------- | ------------------------------------------------------------------ |
    | `sent`         | Sent             | Emails sent.                                                       |
    | `delivered`    | Delivered        | Emails delivered.                                                  |
    | `opened`       | Unique Opens     | Recipients who opened the email, counted once each.                |
    | `clicked`      | Unique Clicks    | Recipients who clicked the email, counted once each.               |
    | `bounced`      | Bounced          | Hard bounces.                                                      |
    | `failed`       | Failed           | Sends that failed.                                                 |
    | `spam`         | Reported as Spam | Recipients who reported the email as spam.                         |
    | `suppressed`   | Suppressed       | Sends suppressed by the [suppression list](/docs/en/suppressions). |
    | `unsubscribed` | Unsubscribed     | Recipients who unsubscribed.                                       |
  </Tab>

  <Tab title="SMS">
    | Field                | Dashboard term       | Description                                                                       |
    | -------------------- | -------------------- | --------------------------------------------------------------------------------- |
    | `sent`               | Sent                 | SMS messages sent.                                                                |
    | `successful`         |                      | Messages OneSignal dispatched to the provider without error.                      |
    | `delivered`          | Delivered            | Messages the provider confirmed delivered.                                        |
    | `undelivered`        | Provider Undelivered | Messages the provider reported as undelivered.                                    |
    | `sms_failed`         | Provider Errored     | Failures the provider reported.                                                   |
    | `errored`            |                      | Sends that errored inside OneSignal before reaching the provider.                 |
    | `failed`             | Failed               | Combined failure count. Roll-up of the OneSignal-side and provider-side failures. |
    | `rejected`           | Rejected             | Messages rejected by the provider or carrier.                                     |
    | `suppressed`         | Suppressed           | Sends suppressed before dispatch.                                                 |
    | `type_sms_delivered` |                      | Deliveries that went out as SMS.                                                  |
    | `type_rcs_delivered` |                      | Deliveries that went out as [RCS](/docs/en/rcs-messaging).                        |
    | `rcs_read`           | Read                 | RCS messages read.                                                                |
    | `clicked`            | Total Clicks         | Clicks on tracked links in the message.                                           |
    | `unique_clicked`     | Unique Clicks        | Unique clicks on tracked links in the message.                                    |

    `clicked` and `unique_clicked` are present only when the message contains tracked links.
  </Tab>

  <Tab title="In-app message">
    `send_iam` nodes report overall totals for the message.

    | Field            | Dashboard term | Description                                                                              |
    | ---------------- | -------------- | ---------------------------------------------------------------------------------------- |
    | `impressions`    | Impressions    | Times the in-app message was displayed.                                                  |
    | `unique_clicked` | Unique Clicks  | Unique element clicks.                                                                   |
    | `ctr`            |                | Click-through rate as `unique_clicked / impressions`. `0` when there are no impressions. |

    Per-element and per-platform breakdowns are not exposed by this endpoint. Use the in-app message report in the dashboard for those.
  </Tab>

  <Tab title="Webhook">
    | Field       | Description                              |
    | ----------- | ---------------------------------------- |
    | `sent`      | Webhook requests sent.                   |
    | `succeeded` | Requests that returned a success status. |
    | `failed`    | Requests that failed.                    |
    | `four_xx`   | Requests that returned a `4xx` status.   |
    | `five_xx`   | Requests that returned a `5xx` status.   |
    | `timeouts`  | Requests that timed out.                 |
  </Tab>
</Tabs>

<Warning>
  Node-level message stats are tracked from 2023-08-20 onward. `message_stats` for a journey activated before that date can be incomplete.
</Warning>

### Reconciling the counts

`waiting`, `completed`, and `exited_early` are separate buckets on each node, so a user is counted in exactly one of them per node. A node's `completed` therefore excludes users who exited early from it, and users still held at the node are not counted as completed.

Node counts do not have to sum to the journey-level counts. `started` counts journey entries, while a user can pass through many nodes, and a re-entering user is counted again on each pass.

### Error responses

| Status | Code                | Description                                                                                                                             |
| ------ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| 404    | `journey-not-found` | No journey with that `id` exists 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" }] }`.


## OpenAPI

````yaml GET /apps/{app_id}/journeys/{id}/stats
openapi: 3.1.0
info:
  title: api.onesignal.com
  version: '11.6'
servers:
  - url: https://api.onesignal.com
security:
  - {}
paths:
  /apps/{app_id}/journeys/{id}/stats:
    get:
      summary: View journey stats
      description: >-
        Retrieve performance stats for a single journey: journey-level entry and
        exit counts, per-node counts keyed by node `id`, per-branch counts keyed
        by branch `id`, and channel delivery stats for message-sending nodes.
        The response carries no definition detail, so join it by `id` against
        the journey from [View journey](/reference/view-journey).
      operationId: view-journey-stats
      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: id
          in: path
          description: UUID of the journey to retrieve stats for.
          required: true
          schema:
            type: string
            default: YOUR_JOURNEY_ID
        - 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
      responses:
        '200':
          description: '200'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JourneyStats'
              examples:
                Result:
                  value:
                    id: 0a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9
                    started: 1000
                    completed: 820
                    exited_early: 60
                    nodes:
                      11111111-0000-0000-0000-000000000001:
                        kind: send_push
                        waiting: 0
                        completed: 980
                        exited_early: 20
                        message_stats:
                          totals:
                            sent: 1000
                            delivered: 940
                            confirmed_delivered: 902
                            clicked: 210
                            failed: 45
                            unsubscribed: 12
                            frequency_capped: 3
                      11111111-0000-0000-0000-000000000002:
                        kind: wait
                        waiting: 120
                        completed: 820
                        exited_early: 40
                    branches: {}
        '404':
          description: '404'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JourneyCodedErrorResponse'
              example:
                errors:
                  - code: journey-not-found
                    title: Journey not found
                    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
      x-codeSamples:
        - lang: typescript
          label: Node.js SDK
          source: |-
            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";
            // string | UUID of the journey to retrieve stats for.
            const journeyId: string = "YOUR_JOURNEY_ID";

            try {
              const response = await apiInstance.viewJourneyStats(appId, journeyId);
              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("viewJourneyStats failed: HTTP " + e.code, e.errorMessages);
              } else {
                throw e;
              }
            }
        - lang: python
          label: Python SDK
          source: >-
            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. 
                journey_id = "YOUR_JOURNEY_ID" # UUID of the journey to retrieve stats for. 

                try:
                    # View journey stats
                    api_response = api_instance.view_journey_stats(app_id, journey_id)
                    pprint(api_response)
                except onesignal.ApiException as e:
                    print("Exception when calling DefaultApi->view_journey_stats: %s\n" % e)
                    print("Status Code: %s" % e.status)
                    print("Response Body: %s" % e.body)
        - lang: php
          label: PHP SDK
          source: >-
            <?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.

            $journey_id = 'YOUR_JOURNEY_ID'; // string | UUID of the journey to
            retrieve stats for.


            try {
                $result = $apiInstance->viewJourneyStats($app_id, $journey_id);
                print_r($result);
            } catch (\onesignal\client\ApiException $e) {
                echo 'Exception when calling DefaultApi->viewJourneyStats: ', $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->viewJourneyStats: ', $e->getMessage(), PHP_EOL;
            }
        - lang: go
          label: Go SDK
          source: |-
            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.
                journeyId := "YOUR_JOURNEY_ID" // string | UUID of the journey to retrieve stats for.

                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.ViewJourneyStats(restAuth, appId, journeyId).Execute()

                if err != nil {
                    fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.ViewJourneyStats``: %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 `ViewJourneyStats`: JourneyStats
                fmt.Fprintf(os.Stdout, "Response from `DefaultApi.ViewJourneyStats`: %v\n", resp)
            }
        - lang: ruby
          label: Ruby SDK
          source: >-
            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.

            journey_id = 'YOUR_JOURNEY_ID' # String | UUID of the journey to
            retrieve stats for.


            begin
              # View journey stats
              result = api_instance.view_journey_stats(app_id, journey_id)
              p result
            rescue OneSignal::ApiError => e
              puts "Error when calling DefaultApi->view_journey_stats: #{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
        - lang: java
          label: Java SDK
          source: |-
            // 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.
                String journeyId = "YOUR_JOURNEY_ID"; // String | UUID of the journey to retrieve stats for.
                try {
                  JourneyStats result = apiInstance.viewJourneyStats(appId, journeyId);
                  System.out.println(result);
                } catch (ApiException e) {
                  System.err.println("Exception when calling DefaultApi#viewJourneyStats");
                  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();
                }
              }
            }
        - lang: csharp
          label: C# SDK
          source: |-
            using System;
            using System.Collections.Generic;
            using System.Diagnostics;
            using OneSignalApi.Api;
            using OneSignalApi.Client;
            using OneSignalApi.Model;

            namespace Example
            {
                public class ViewJourneyStatsExample
                {
                    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 journeyId = "YOUR_JOURNEY_ID";  // string | UUID of the journey to retrieve stats for.

                        try
                        {
                            // View journey stats
                            JourneyStats result = apiInstance.ViewJourneyStats(appId, journeyId);
                            Debug.WriteLine(result);
                        }
                        catch (ApiException  e)
                        {
                            Debug.Print("Exception when calling DefaultApi.ViewJourneyStats: " + 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);
                        }
                    }
                }
            }
        - lang: rust
          label: Rust SDK
          source: |-
            use onesignal_rust_api::apis::configuration::Configuration;
            use onesignal_rust_api::apis::default_api;


            #[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 journey_id: &str = "YOUR_JOURNEY_ID";

                match default_api::view_journey_stats(&configuration, app_id, journey_id).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!("view_journey_stats failed: {:?}", e.error_messages());
                    }
                    Err(e) => eprintln!("view_journey_stats failed: {:?}", e),
                }
            }
components:
  schemas:
    JourneyStats:
      type: object
      description: >-
        Journey-level counts plus flat, id-keyed maps of node and branch stats.
        Contains no definition detail; join it by `id` against the journey from
        [View journey](/reference/view-journey).
      properties:
        id:
          type: string
          description: UUID of the journey these stats belong to.
        started:
          type: integer
          description: Users who entered the journey.
        completed:
          type: integer
          description: Users who reached the end of the journey normally.
        exited_early:
          type: integer
          description: Users who left the journey through an early exit rule.
        nodes:
          type: object
          description: >-
            Node stats keyed by node `id`. Includes every node in the graph, at
            any nesting depth.
          additionalProperties:
            $ref: '#/components/schemas/JourneyNodeStats'
        branches:
          type: object
          description: >-
            Branch stats keyed by branch `id`. Empty for a journey with no
            branching nodes.
          additionalProperties:
            $ref: '#/components/schemas/JourneyBranchStats'
    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.
    JourneyNodeStats:
      type: object
      description: >-
        Stats for a single node. Keyed in the response by the node's
        server-assigned `id`.
      properties:
        kind:
          type: string
          enum:
            - wait
            - time_window
            - send_push
            - send_email
            - send_sms
            - send_iam
            - send_webhook
            - tag
            - split_range
            - yes_no
            - wait_until
          description: >-
            Node kind, repeated here so stats can be read without joining
            against the journey definition.
        waiting:
          type: integer
          description: >-
            Users currently held at this node, i.e. those who entered but have
            neither advanced to the next node nor exited early.
        completed:
          type: integer
          description: Users who advanced past this node normally.
        exited_early:
          type: integer
          description: >-
            Users who left the journey from this node through an early exit
            rule.
        message_stats:
          $ref: '#/components/schemas/JourneyMessageStats'
    JourneyBranchStats:
      type: object
      description: >-
        Stats for a single branch of a branching node. Keyed in the response by
        the branch's server-assigned `id`.
      properties:
        completed:
          type: integer
          description: Users who took this branch.
    JourneyMessageStats:
      type: object
      description: >-
        Delivery stats for a message-sending node. Present only on `send_push`,
        `send_email`, `send_sms`, `send_iam`, and `send_webhook` nodes. The keys
        inside `totals` depend on the node's channel.
      properties:
        totals:
          type: object
          description: >-
            All-time totals for this node, keyed by channel-specific stat name.
            See [View journey stats](/reference/view-journey-stats) for the key
            set per channel.
          additionalProperties:
            type: number

````