Index: asterisk-22.8.2/main/stasis_channels.c
===================================================================
--- asterisk-22.8.2.orig/main/stasis_channels.c
+++ asterisk-22.8.2/main/stasis_channels.c
@@ -1823,6 +1823,47 @@ struct ast_ari_transfer_message *ast_ari
 	return msg;
 }
 
+static struct ast_json *moh_start_to_json(struct stasis_message *message,
+	const struct stasis_message_sanitizer *sanitize)
+{
+	struct ast_channel_blob *channel_blob = stasis_message_data(message);
+	struct ast_json *blob = channel_blob->blob;
+	struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
+	const char *musicclass = ast_json_string_get(ast_json_object_get(blob, "class"));
+	const struct timeval *tv = stasis_message_timestamp(message);
+	struct ast_json *json_channel;
+
+	json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
+	if (!json_channel) {
+		return NULL;
+	}
+
+	return ast_json_pack("{s: s, s: o, s: s, s: o}",
+		"type", "ChannelMohStart",
+		"timestamp", ast_json_timeval(*tv, NULL),
+		"moh_class", S_OR(musicclass, "N/A"),
+		"channel", json_channel);
+}
+
+static struct ast_json *moh_stop_to_json(struct stasis_message *message,
+	const struct stasis_message_sanitizer *sanitize)
+{
+	struct ast_channel_blob *channel_blob = stasis_message_data(message);
+	struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
+	const struct timeval *tv = stasis_message_timestamp(message);
+	struct ast_json *json_channel;
+
+	json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
+	if (!json_channel) {
+		return NULL;
+	}
+
+	return ast_json_pack("{s: s, s: o, s: o}",
+		"type", "ChannelMohStop",
+		"timestamp", ast_json_timeval(*tv, NULL),
+		"channel", json_channel);
+}
+
 /*!
  * @{ \brief Define channel message types.
  */
@@ -1854,8 +1895,12 @@ STASIS_MESSAGE_TYPE_DEFN(ast_channel_cha
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type,
+	.to_json = moh_start_to_json,
+	);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type,
+	.to_json = moh_stop_to_json,
+	);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_mixmonitor_start_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_mixmonitor_stop_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_mixmonitor_mute_type);
Index: asterisk-22.8.2/rest-api/api-docs/events.json
===================================================================
--- asterisk-22.8.2.orig/rest-api/api-docs/events.json
+++ asterisk-22.8.2/rest-api/api-docs/events.json
@@ -203,7 +203,9 @@
 				"ChannelConnectedLine",
 				"PeerStatusChange",
 				"ChannelTransfer",
-				"RESTResponse"
+				"RESTResponse",
+				"ChannelMohStart",
+				"ChannelMohStop"
 			]
 		},
 		"ContactInfo": {
@@ -1179,6 +1181,33 @@
 					"description": "Response message body"
 				}
 			}
+		},
+		"ChannelMohStart": {
+			"id": "ChannelMohStart",
+			"description": "MOH started on the channel.",
+			"properties": {
+				"channel": {
+					"required": true,
+					"type": "Channel",
+					"description": "The channel on which the MOH started."
+				},
+				"moh_class": {
+					"required": true,
+					"type": "string",
+					"description": "The name of the MOH class that started"
+				}
+			}
+		},
+		"ChannelMohStop": {
+			"id": "ChannelMohStop",
+			"description": "MOH stopped on the channel.",
+			"properties": {
+				"channel": {
+					"required": true,
+					"type": "Channel",
+					"description": "The channel on which the MOH stopped."
+				}
+			}
 		}
 	}
 }
Index: asterisk-22.8.2/res/ari/ari_model_validators.c
===================================================================
--- asterisk-22.8.2.orig/res/ari/ari_model_validators.c
+++ asterisk-22.8.2/res/ari/ari_model_validators.c
@@ -4844,6 +4844,212 @@ ari_validator ast_ari_validate_channel_l
 	return ast_ari_validate_channel_left_bridge;
 }
 
+int ast_ari_validate_channel_moh_start(struct ast_json *json)
+{
+	int res = 1;
+	struct ast_json_iter *iter;
+	int has_type = 0;
+	int has_application = 0;
+	int has_timestamp = 0;
+	int has_channel = 0;
+	int has_moh_class = 0;
+
+	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+		if (strcmp("asterisk_id", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStart field asterisk_id failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_type = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStart field type failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_application = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStart field application failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_timestamp = 1;
+			prop_is_valid = ast_ari_validate_date(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStart field timestamp failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_channel = 1;
+			prop_is_valid = ast_ari_validate_channel(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStart field channel failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("moh_class", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_moh_class = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStart field moh_class failed validation\n");
+				res = 0;
+			}
+		} else
+		{
+			ast_log(LOG_ERROR,
+				"ARI ChannelMohStart has undocumented field %s\n",
+				ast_json_object_iter_key(iter));
+			res = 0;
+		}
+	}
+
+	if (!has_type) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStart missing required field type\n");
+		res = 0;
+	}
+
+	if (!has_application) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStart missing required field application\n");
+		res = 0;
+	}
+
+	if (!has_timestamp) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStart missing required field timestamp\n");
+		res = 0;
+	}
+
+	if (!has_channel) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStart missing required field channel\n");
+		res = 0;
+	}
+
+	if (!has_moh_class) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStart missing required field moh_class\n");
+		res = 0;
+	}
+
+	return res;
+}
+
+ari_validator ast_ari_validate_channel_moh_start_fn(void)
+{
+	return ast_ari_validate_channel_moh_start;
+}
+
+int ast_ari_validate_channel_moh_stop(struct ast_json *json)
+{
+	int res = 1;
+	struct ast_json_iter *iter;
+	int has_type = 0;
+	int has_application = 0;
+	int has_timestamp = 0;
+	int has_channel = 0;
+
+	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+		if (strcmp("asterisk_id", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStop field asterisk_id failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_type = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStop field type failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_application = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStop field application failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_timestamp = 1;
+			prop_is_valid = ast_ari_validate_date(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStop field timestamp failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_channel = 1;
+			prop_is_valid = ast_ari_validate_channel(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelMohStop field channel failed validation\n");
+				res = 0;
+			}
+		} else
+		{
+			ast_log(LOG_ERROR,
+				"ARI ChannelMohStop has undocumented field %s\n",
+				ast_json_object_iter_key(iter));
+			res = 0;
+		}
+	}
+
+	if (!has_type) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStop missing required field type\n");
+		res = 0;
+	}
+
+	if (!has_application) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStop missing required field application\n");
+		res = 0;
+	}
+
+	if (!has_timestamp) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStop missing required field timestamp\n");
+		res = 0;
+	}
+
+	if (!has_channel) {
+		ast_log(LOG_ERROR, "ARI ChannelMohStop missing required field channel\n");
+		res = 0;
+	}
+
+	return res;
+}
+
+ari_validator ast_ari_validate_channel_moh_stop_fn(void)
+{
+	return ast_ari_validate_channel_moh_stop;
+}
+
 int ast_ari_validate_channel_state_change(struct ast_json *json)
 {
 	int res = 1;
@@ -6318,6 +6524,12 @@ int ast_ari_validate_event(struct ast_js
 	if (strcmp("ChannelLeftBridge", discriminator) == 0) {
 		return ast_ari_validate_channel_left_bridge(json);
 	} else
+	if (strcmp("ChannelMohStart", discriminator) == 0) {
+		return ast_ari_validate_channel_moh_start(json);
+	} else
+	if (strcmp("ChannelMohStop", discriminator) == 0) {
+		return ast_ari_validate_channel_moh_stop(json);
+	} else
 	if (strcmp("ChannelStateChange", discriminator) == 0) {
 		return ast_ari_validate_channel_state_change(json);
 	} else
@@ -6540,6 +6752,12 @@ int ast_ari_validate_message(struct ast_
 	if (strcmp("ChannelLeftBridge", discriminator) == 0) {
 		return ast_ari_validate_channel_left_bridge(json);
 	} else
+	if (strcmp("ChannelMohStart", discriminator) == 0) {
+		return ast_ari_validate_channel_moh_start(json);
+	} else
+	if (strcmp("ChannelMohStop", discriminator) == 0) {
+		return ast_ari_validate_channel_moh_stop(json);
+	} else
 	if (strcmp("ChannelStateChange", discriminator) == 0) {
 		return ast_ari_validate_channel_state_change(json);
 	} else
Index: asterisk-22.8.2/res/ari/ari_model_validators.h
===================================================================
--- asterisk-22.8.2.orig/res/ari/ari_model_validators.h
+++ asterisk-22.8.2/res/ari/ari_model_validators.h
@@ -912,6 +912,38 @@ int ast_ari_validate_channel_left_bridge
 ari_validator ast_ari_validate_channel_left_bridge_fn(void);
 
 /*!
+ * \brief Validator for ChannelMohStart.
+ *
+ * MOH started on the channel.
+ *
+ * \param json JSON object to validate.
+ * \retval True (non-zero) if valid.
+ * \retval False (zero) if invalid.
+ */
+int ast_ari_validate_channel_moh_start(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_moh_start().
+ */
+ari_validator ast_ari_validate_channel_moh_start_fn(void);
+
+/*!
+ * \brief Validator for ChannelMohStop.
+ *
+ * MOH stopped on the channel.
+ *
+ * \param json JSON object to validate.
+ * \retval True (non-zero) if valid.
+ * \retval False (zero) if invalid.
+ */
+int ast_ari_validate_channel_moh_stop(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_moh_stop().
+ */
+ari_validator ast_ari_validate_channel_moh_stop_fn(void);
+
+/*!
  * \brief Validator for ChannelStateChange.
  *
  * Notification of a channel's state change.
@@ -1794,6 +1826,19 @@ ari_validator ast_ari_validate_applicati
  * - timestamp: Date (required)
  * - bridge: Bridge (required)
  * - channel: Channel (required)
+ * ChannelMohStart
+ * - asterisk_id: string
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date (required)
+ * - channel: Channel (required)
+ * - moh_class: string (required)
+ * ChannelMohStop
+ * - asterisk_id: string
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date (required)
+ * - channel: Channel (required)
  * ChannelStateChange
  * - asterisk_id: string
  * - type: string (required)
