diff --git a/res/ari/resource_asterisk.h b/res/ari/resource_asterisk.h
index 69539525e58aa9276eeb6b888cad47ef635b02e1..d2f316a6bcc6496dcc2c5e92ee4d98c4de20d8d2 100644
--- a/res/ari/resource_asterisk.h
+++ b/res/ari/resource_asterisk.h
@@ -41,8 +41,12 @@
 
 /*! \brief Argument struct for ast_ari_get_asterisk_info() */
 struct ast_get_asterisk_info_args {
-	/*! \brief Filter information returned */
-	const char *only;
+	/*! \brief Array of Filter information returned */
+	const char **only;
+	/*! \brief Length of only array. */
+	size_t only_count;
+	/*! \brief Parsing context for only. */
+	char *only_parse;
 };
 /*!
  * \brief Gets Asterisk system information.
diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c
index 7730d0cd9d1c8607ba465ad97b72b82ffe6ef96a..e4c7194ff2b06e7daa018776891152d27683ba18 100644
--- a/res/ari/resource_bridges.c
+++ b/res/ari/resource_bridges.c
@@ -1,4 +1,4 @@
-/* -*- C -*-
+/*
  * Asterisk -- An open source telephony toolkit.
  *
  * Copyright (C) 2012 - 2013, Digium, Inc.
@@ -107,33 +107,95 @@ static struct stasis_app_control *find_channel_control(
 	return control;
 }
 
+struct control_list {
+	size_t count;
+	struct stasis_app_control *controls[];
+};
+
+static void control_list_dtor(void *obj) {
+	struct control_list *list = obj;
+	size_t i;
+
+	for (i = 0; i < list->count; ++i) {
+		ao2_cleanup(list->controls[i]);
+		list->controls[i] = NULL;
+	}
+}
+
+static struct control_list *control_list_create(struct ast_ari_response *response, size_t count, const char **channels) {
+	RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
+	size_t i;
+
+	if (count == 0 || !channels) {
+		ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
+		return NULL;
+	}
+
+	list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor);
+	if (!list) {
+		ast_ari_response_alloc_failed(response);
+		return NULL;
+	}
+
+	for (i = 0; i < count; ++i) {
+		if (ast_strlen_zero(channels[i])) {
+			continue;
+		}
+		list->controls[list->count] =
+			find_channel_control(response, channels[i]);
+		if (!list->controls[list->count]) {
+			return NULL;
+		}
+		++list->count;
+	}
+
+	if (list->count == 0) {
+		ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
+		return NULL;
+	}
+
+	ao2_ref(list, +1);
+	return list;
+}
+
 void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response)
 {
 	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+	RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
+	size_t i;
+
 	if (!bridge) {
+		/* Response filled in by find_bridge */
 		return;
 	}
 
-	control = find_channel_control(response, args->channel);
-	if (!control) {
+	list = control_list_create(response, args->channel_count, args->channel);
+	if (!list) {
+		/* Response filled in by control_list_create() */
 		return;
 	}
 
-	stasis_app_control_add_channel_to_bridge(control, bridge);
+	for (i = 0; i < list->count; ++i) {
+		stasis_app_control_add_channel_to_bridge(list->controls[i], bridge);
+	}
+
 	ast_ari_response_no_content(response);
 }
 
 void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response)
 {
 	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
-	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+	RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
+	size_t i;
+
 	if (!bridge) {
+		/* Response filled in by find_bridge */
 		return;
 	}
 
-	control = find_channel_control(response, args->channel);
-	if (!control) {
+	list = control_list_create(response, args->channel_count, args->channel);
+	if (!list) {
+		/* Response filled in by control_list_create() */
 		return;
 	}
 
@@ -141,9 +203,14 @@ void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast
 	 * the bridge the channel is in. This will be possible once the bridge uniqueid
 	 * is added to the channel snapshot. A 409 response should be issued if the bridge
 	 * uniqueids don't match */
-	if (stasis_app_control_remove_channel_from_bridge(control, bridge)) {
-		ast_ari_response_error(response, 500, "Internal Error",
-			"Could not remove channel from bridge");
+	for (i = 0; i < list->count; ++i) {
+		if (stasis_app_control_remove_channel_from_bridge(list->controls[i], bridge)) {
+			ast_ari_response_error(response, 500, "Internal Error",
+				"Could not remove channel from bridge");
+		}
+	}
+
+	if (response->response_code) {
 		return;
 	}
 
diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h
index 892a3f2696d626afcc7aadf0a4ab9322c7b84f59..d124324133f786b189d4f2348287ac8ed105225d 100644
--- a/res/ari/resource_bridges.h
+++ b/res/ari/resource_bridges.h
@@ -97,8 +97,12 @@ void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridg
 struct ast_add_channel_to_bridge_args {
 	/*! \brief Bridge's id */
 	const char *bridge_id;
-	/*! \brief Channel's id */
-	const char *channel;
+	/*! \brief Array of Ids of channels to add to bridge */
+	const char **channel;
+	/*! \brief Length of channel array. */
+	size_t channel_count;
+	/*! \brief Parsing context for channel. */
+	char *channel_parse;
 };
 /*!
  * \brief Add a channel to a bridge.
@@ -112,8 +116,12 @@ void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_
 struct ast_remove_channel_from_bridge_args {
 	/*! \brief Bridge's id */
 	const char *bridge_id;
-	/*! \brief Channel's id */
-	const char *channel;
+	/*! \brief Array of Ids of channels to remove from bridge */
+	const char **channel;
+	/*! \brief Length of channel array. */
+	size_t channel_count;
+	/*! \brief Parsing context for channel. */
+	char *channel_parse;
 };
 /*!
  * \brief Remove a channel from a bridge.
diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c
index e5490b54618eecfb4e43ab2081453486636b62e1..dd474c3ce52c49ba02603f0df57eab2b59aacf85 100644
--- a/res/ari/resource_events.c
+++ b/res/ari/resource_events.c
@@ -143,35 +143,28 @@ static void app_handler(void *data, const char *app_name,
 /*!
  * \brief Register for all of the apps given.
  * \param session Session info struct.
- * \param app_list Comma seperated list of app names to register.
+ * \param app_name Name of application to register.
  */
-static int session_register_apps(struct event_session *session,
-				 const char *app_list)
+static int session_register_app(struct event_session *session,
+				 const char *app_name)
 {
-	RAII_VAR(char *, to_free, NULL, ast_free);
-	char *apps, *app_name;
 	SCOPED_AO2LOCK(lock, session);
 
 	ast_assert(session->ws_session != NULL);
 	ast_assert(session->websocket_apps != NULL);
 
-	if (!app_list) {
+	if (ast_strlen_zero(app_name)) {
 		return -1;
 	}
 
-	to_free = apps = ast_strdup(app_list);
-	if (!apps) {
-		ast_ari_websocket_session_write(session->ws_session, ast_ari_oom_json());
+	if (ast_str_container_add(session->websocket_apps, app_name)) {
+		ast_ari_websocket_session_write(session->ws_session,
+			ast_ari_oom_json());
 		return -1;
 	}
-	while ((app_name = strsep(&apps, ","))) {
-		if (ast_str_container_add(session->websocket_apps, app_name)) {
-			ast_ari_websocket_session_write(session->ws_session, ast_ari_oom_json());
-			return -1;
-		}
 
-		stasis_app_register(app_name, app_handler, session);
-	}
+	stasis_app_register(app_name, app_handler, session);
+
 	return 0;
 }
 
@@ -182,6 +175,7 @@ void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *ws_sess
 	RAII_VAR(struct event_session *, session, NULL, session_cleanup);
 	struct ast_json *msg;
 	int res;
+	size_t i;
 
 	ast_debug(3, "/events WebSocket connection\n");
 
@@ -191,7 +185,15 @@ void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *ws_sess
 		return;
 	}
 
-	if (!args->app) {
+	res = 0;
+	for (i = 0; i < args->app_count; ++i) {
+		if (ast_strlen_zero(args->app[i])) {
+			continue;
+		}
+		res |= session_register_app(session, args->app[i]);
+	}
+
+	if (ao2_container_count(session->websocket_apps) == 0) {
 		RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
 
 		msg = ast_json_pack("{s: s, s: [s]}",
@@ -205,7 +207,6 @@ void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *ws_sess
 		return;
 	}
 
-	res = session_register_apps(session, args->app);
 	if (res != 0) {
 		ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
 		return;
diff --git a/res/ari/resource_events.h b/res/ari/resource_events.h
index 554ed9a87a5709c8c5a8d6846765a5cae7880737..ac7600e03ed9545eceb108f6f90279cf976b64b3 100644
--- a/res/ari/resource_events.h
+++ b/res/ari/resource_events.h
@@ -41,8 +41,12 @@
 
 /*! \brief Argument struct for ast_ari_event_websocket() */
 struct ast_event_websocket_args {
-	/*! \brief Comma seperated list of applications to subscribe to. */
-	const char *app;
+	/*! \brief Array of Applications to subscribe to. */
+	const char **app;
+	/*! \brief Length of app array. */
+	size_t app_count;
+	/*! \brief Parsing context for app. */
+	char *app_parse;
 };
 /*!
  * \brief WebSocket connection for events.
diff --git a/res/ari/resource_sounds.h b/res/ari/resource_sounds.h
index 7cb22fb716420524cae07b2550dc4f7a7509d059..fa7cda23cedd2c451caa8a06903909b205a892b5 100644
--- a/res/ari/resource_sounds.h
+++ b/res/ari/resource_sounds.h
@@ -41,7 +41,9 @@
 
 /*! \brief Argument struct for ast_ari_get_sounds() */
 struct ast_get_sounds_args {
+	/*! \brief Lookup sound for a specific language. */
 	const char *lang;
+	/*! \brief Lookup sound in a specific format. */
 	const char *format;
 };
 /*!
diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c
index 2c125188be416c0dbda5ce92b4d3fb4e3b6bc439..dce634e8ae802d0405b88b1aa085bbd218eae2a5 100644
--- a/res/res_ari_asterisk.c
+++ b/res/res_ari_asterisk.c
@@ -41,6 +41,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_asterisk.h"
@@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 /*!
  * \brief Parameter parsing callback for /asterisk/info.
  * \param get_params GET parameters in the HTTP request.
@@ -59,17 +62,48 @@ static void ast_ari_get_asterisk_info_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_asterisk_info_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_asterisk_info_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "only") == 0) {
-			args.only = (i->value);
+			/* Parse comma separated list */
+			char *vals[MAX_VALS];
+			size_t j;
+
+			args.only_parse = ast_strdup(i->value);
+			if (!args.only_parse) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			args.only_count = ast_app_separate_args(
+				args.only_parse, ',', vals, ARRAY_LEN(vals));
+			if (args.only_count == 0) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			if (args.only_count >= MAX_VALS) {
+				ast_ari_response_error(response, 400,
+					"Bad Request",
+					"Too many values for only");
+				goto fin;
+			}
+
+			args.only = ast_malloc(sizeof(*args.only) * args.only_count);
+			if (!args.only) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			for (j = 0; j < args.only_count; ++j) {
+				args.only[j] = (vals[j]);
+			}
 		} else
 		{}
 	}
@@ -101,6 +135,11 @@ static void ast_ari_get_asterisk_info_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	ast_free(args.only_parse);
+	ast_free(args.only);
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /asterisk/variable.
@@ -113,14 +152,13 @@ static void ast_ari_get_global_var_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_global_var_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_global_var_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "variable") == 0) {
 			args.variable = (i->value);
@@ -155,6 +193,9 @@ static void ast_ari_get_global_var_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /asterisk/variable.
@@ -167,14 +208,13 @@ static void ast_ari_set_global_var_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_set_global_var_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_set_global_var_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "variable") == 0) {
 			args.variable = (i->value);
@@ -212,6 +252,9 @@ static void ast_ari_set_global_var_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 
 /*! \brief REST handler for /api-docs/asterisk.{format} */
diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c
index f2ee8c03add101d95423789606b4435bbf40b055..57dc6a48da77bfa3a7c4ccbd89c368ce2eb08135 100644
--- a/res/res_ari_bridges.c
+++ b/res/res_ari_bridges.c
@@ -41,6 +41,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_bridges.h"
@@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 /*!
  * \brief Parameter parsing callback for /bridges.
  * \param get_params GET parameters in the HTTP request.
@@ -59,12 +62,12 @@ static void ast_ari_get_bridges_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_bridges_args args = {};
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_bridges_args args = {};
 	ast_ari_get_bridges(headers, &args, response);
 #if defined(AST_DEVMODE)
 	code = response->response_code;
@@ -93,6 +96,9 @@ static void ast_ari_get_bridges_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /bridges.
@@ -105,14 +111,13 @@ static void ast_ari_new_bridge_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_new_bridge_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_new_bridge_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "type") == 0) {
 			args.type = (i->value);
@@ -147,6 +152,9 @@ static void ast_ari_new_bridge_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /bridges/{bridgeId}.
@@ -159,14 +167,13 @@ static void ast_ari_get_bridge_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_bridge_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_bridge_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "bridgeId") == 0) {
 			args.bridge_id = (i->value);
@@ -202,6 +209,9 @@ static void ast_ari_get_bridge_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /bridges/{bridgeId}.
@@ -214,14 +224,13 @@ static void ast_ari_delete_bridge_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_delete_bridge_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_delete_bridge_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "bridgeId") == 0) {
 			args.bridge_id = (i->value);
@@ -257,6 +266,9 @@ static void ast_ari_delete_bridge_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /bridges/{bridgeId}/addChannel.
@@ -269,17 +281,48 @@ static void ast_ari_add_channel_to_bridge_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_add_channel_to_bridge_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_add_channel_to_bridge_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "channel") == 0) {
-			args.channel = (i->value);
+			/* Parse comma separated list */
+			char *vals[MAX_VALS];
+			size_t j;
+
+			args.channel_parse = ast_strdup(i->value);
+			if (!args.channel_parse) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			args.channel_count = ast_app_separate_args(
+				args.channel_parse, ',', vals, ARRAY_LEN(vals));
+			if (args.channel_count == 0) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			if (args.channel_count >= MAX_VALS) {
+				ast_ari_response_error(response, 400,
+					"Bad Request",
+					"Too many values for channel");
+				goto fin;
+			}
+
+			args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count);
+			if (!args.channel) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			for (j = 0; j < args.channel_count; ++j) {
+				args.channel[j] = (vals[j]);
+			}
 		} else
 		{}
 	}
@@ -320,6 +363,11 @@ static void ast_ari_add_channel_to_bridge_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	ast_free(args.channel_parse);
+	ast_free(args.channel);
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /bridges/{bridgeId}/removeChannel.
@@ -332,17 +380,48 @@ static void ast_ari_remove_channel_from_bridge_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_remove_channel_from_bridge_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_remove_channel_from_bridge_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "channel") == 0) {
-			args.channel = (i->value);
+			/* Parse comma separated list */
+			char *vals[MAX_VALS];
+			size_t j;
+
+			args.channel_parse = ast_strdup(i->value);
+			if (!args.channel_parse) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			args.channel_count = ast_app_separate_args(
+				args.channel_parse, ',', vals, ARRAY_LEN(vals));
+			if (args.channel_count == 0) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			if (args.channel_count >= MAX_VALS) {
+				ast_ari_response_error(response, 400,
+					"Bad Request",
+					"Too many values for channel");
+				goto fin;
+			}
+
+			args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count);
+			if (!args.channel) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			for (j = 0; j < args.channel_count; ++j) {
+				args.channel[j] = (vals[j]);
+			}
 		} else
 		{}
 	}
@@ -380,6 +459,11 @@ static void ast_ari_remove_channel_from_bridge_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	ast_free(args.channel_parse);
+	ast_free(args.channel);
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /bridges/{bridgeId}/play.
@@ -392,14 +476,13 @@ static void ast_ari_play_on_bridge_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_play_on_bridge_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_play_on_bridge_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "media") == 0) {
 			args.media = (i->value);
@@ -451,6 +534,9 @@ static void ast_ari_play_on_bridge_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /bridges/{bridgeId}/record.
@@ -463,14 +549,13 @@ static void ast_ari_record_bridge_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_record_bridge_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_record_bridge_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "name") == 0) {
 			args.name = (i->value);
@@ -529,6 +614,9 @@ static void ast_ari_record_bridge_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 
 /*! \brief REST handler for /api-docs/bridges.{format} */
diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c
index 4c322ea2a0e26febfa649853865cbfaf0e0bc3bd..8a6687bc202b4e11493f25e340b3b27c6c484161 100644
--- a/res/res_ari_channels.c
+++ b/res/res_ari_channels.c
@@ -41,6 +41,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_channels.h"
@@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 /*!
  * \brief Parameter parsing callback for /channels.
  * \param get_params GET parameters in the HTTP request.
@@ -59,12 +62,12 @@ static void ast_ari_get_channels_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_channels_args args = {};
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_channels_args args = {};
 	ast_ari_get_channels(headers, &args, response);
 #if defined(AST_DEVMODE)
 	code = response->response_code;
@@ -93,6 +96,9 @@ static void ast_ari_get_channels_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels.
@@ -105,14 +111,13 @@ static void ast_ari_originate_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_originate_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_originate_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "endpoint") == 0) {
 			args.endpoint = (i->value);
@@ -169,6 +174,9 @@ static void ast_ari_originate_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}.
@@ -181,14 +189,13 @@ static void ast_ari_get_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "channelId") == 0) {
 			args.channel_id = (i->value);
@@ -224,6 +231,9 @@ static void ast_ari_get_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}.
@@ -236,14 +246,13 @@ static void ast_ari_delete_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_delete_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_delete_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "channelId") == 0) {
 			args.channel_id = (i->value);
@@ -279,6 +288,9 @@ static void ast_ari_delete_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/dial.
@@ -291,14 +303,13 @@ static void ast_ari_dial_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_dial_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_dial_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "endpoint") == 0) {
 			args.endpoint = (i->value);
@@ -350,6 +361,9 @@ static void ast_ari_dial_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/continue.
@@ -362,14 +376,13 @@ static void ast_ari_continue_in_dialplan_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_continue_in_dialplan_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_continue_in_dialplan_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "context") == 0) {
 			args.context = (i->value);
@@ -418,6 +431,9 @@ static void ast_ari_continue_in_dialplan_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/answer.
@@ -430,14 +446,13 @@ static void ast_ari_answer_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_answer_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_answer_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "channelId") == 0) {
 			args.channel_id = (i->value);
@@ -474,6 +489,9 @@ static void ast_ari_answer_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/mute.
@@ -486,14 +504,13 @@ static void ast_ari_mute_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_mute_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_mute_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "direction") == 0) {
 			args.direction = (i->value);
@@ -536,6 +553,9 @@ static void ast_ari_mute_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/unmute.
@@ -548,14 +568,13 @@ static void ast_ari_unmute_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_unmute_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_unmute_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "direction") == 0) {
 			args.direction = (i->value);
@@ -598,6 +617,9 @@ static void ast_ari_unmute_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/hold.
@@ -610,14 +632,13 @@ static void ast_ari_hold_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_hold_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_hold_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "channelId") == 0) {
 			args.channel_id = (i->value);
@@ -654,6 +675,9 @@ static void ast_ari_hold_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/unhold.
@@ -666,14 +690,13 @@ static void ast_ari_unhold_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_unhold_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_unhold_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "channelId") == 0) {
 			args.channel_id = (i->value);
@@ -710,6 +733,9 @@ static void ast_ari_unhold_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/mohstart.
@@ -722,14 +748,13 @@ static void ast_ari_moh_start_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_moh_start_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_moh_start_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "mohClass") == 0) {
 			args.moh_class = (i->value);
@@ -772,6 +797,9 @@ static void ast_ari_moh_start_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/mohstop.
@@ -784,14 +812,13 @@ static void ast_ari_moh_stop_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_moh_stop_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_moh_stop_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "channelId") == 0) {
 			args.channel_id = (i->value);
@@ -828,6 +855,9 @@ static void ast_ari_moh_stop_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/play.
@@ -840,14 +870,13 @@ static void ast_ari_play_on_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_play_on_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_play_on_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "media") == 0) {
 			args.media = (i->value);
@@ -899,6 +928,9 @@ static void ast_ari_play_on_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/record.
@@ -911,14 +943,13 @@ static void ast_ari_record_channel_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_record_channel_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_record_channel_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "name") == 0) {
 			args.name = (i->value);
@@ -980,6 +1011,9 @@ static void ast_ari_record_channel_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/variable.
@@ -992,14 +1026,13 @@ static void ast_ari_get_channel_var_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_channel_var_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_channel_var_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "variable") == 0) {
 			args.variable = (i->value);
@@ -1042,6 +1075,9 @@ static void ast_ari_get_channel_var_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /channels/{channelId}/variable.
@@ -1054,14 +1090,13 @@ static void ast_ari_set_channel_var_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_set_channel_var_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_set_channel_var_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "variable") == 0) {
 			args.variable = (i->value);
@@ -1107,6 +1142,9 @@ static void ast_ari_set_channel_var_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 
 /*! \brief REST handler for /api-docs/channels.{format} */
diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c
index 8aa758929ebf7d3c36f0b9f2e32fbbf7a866cd4b..a1dd759eb639434ef701b5c5504f59b4e10fac8c 100644
--- a/res/res_ari_endpoints.c
+++ b/res/res_ari_endpoints.c
@@ -41,6 +41,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_endpoints.h"
@@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 /*!
  * \brief Parameter parsing callback for /endpoints.
  * \param get_params GET parameters in the HTTP request.
@@ -59,12 +62,12 @@ static void ast_ari_get_endpoints_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_endpoints_args args = {};
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_endpoints_args args = {};
 	ast_ari_get_endpoints(headers, &args, response);
 #if defined(AST_DEVMODE)
 	code = response->response_code;
@@ -93,6 +96,9 @@ static void ast_ari_get_endpoints_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /endpoints/{tech}.
@@ -105,14 +111,13 @@ static void ast_ari_get_endpoints_by_tech_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_endpoints_by_tech_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_endpoints_by_tech_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "tech") == 0) {
 			args.tech = (i->value);
@@ -147,6 +152,9 @@ static void ast_ari_get_endpoints_by_tech_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /endpoints/{tech}/{resource}.
@@ -159,14 +167,13 @@ static void ast_ari_get_endpoint_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_endpoint_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_endpoint_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "tech") == 0) {
 			args.tech = (i->value);
@@ -204,6 +211,9 @@ static void ast_ari_get_endpoint_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 
 /*! \brief REST handler for /api-docs/endpoints.{format} */
diff --git a/res/res_ari_events.c b/res/res_ari_events.c
index c310fa5f98311adafbda2a29b074e84fb4f1b82e..5cea06f0ed019bf2de1a29943ddffce5cca452e0 100644
--- a/res/res_ari_events.c
+++ b/res/res_ari_events.c
@@ -41,6 +41,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_events.h"
@@ -48,20 +49,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 static void ast_ari_event_websocket_ws_cb(struct ast_websocket *ws_session,
 	struct ast_variable *get_params, struct ast_variable *headers)
 {
-	RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
-	RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
 	struct ast_event_websocket_args args = {};
+	RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
 	struct ast_variable *i;
+	RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
+	RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
 
-	for (i = get_params; i; i = i->next) {
-		if (strcmp(i->name, "app") == 0) {
-			args.app = (i->value);
-		} else
-		{}
+	response = ast_calloc(1, sizeof(*response));
+	if (!response) {
+		ast_log(LOG_ERROR, "Failed to create response.\n");
+		goto fin;
 	}
+
 #if defined(AST_DEVMODE)
 	session = ast_ari_websocket_session_create(ws_session,
 		ast_ari_validate_message_fn());
@@ -70,9 +74,69 @@ static void ast_ari_event_websocket_ws_cb(struct ast_websocket *ws_session,
 #endif
 	if (!session) {
 		ast_log(LOG_ERROR, "Failed to create ARI session\n");
-		return;
+		goto fin;
+	}
+
+	for (i = get_params; i; i = i->next) {
+		if (strcmp(i->name, "app") == 0) {
+			/* Parse comma separated list */
+			char *vals[MAX_VALS];
+			size_t j;
+
+			args.app_parse = ast_strdup(i->value);
+			if (!args.app_parse) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			args.app_count = ast_app_separate_args(
+				args.app_parse, ',', vals, ARRAY_LEN(vals));
+			if (args.app_count == 0) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			if (args.app_count >= MAX_VALS) {
+				ast_ari_response_error(response, 400,
+					"Bad Request",
+					"Too many values for app");
+				goto fin;
+			}
+
+			args.app = ast_malloc(sizeof(*args.app) * args.app_count);
+			if (!args.app) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			for (j = 0; j < args.app_count; ++j) {
+				args.app[j] = (vals[j]);
+			}
+		} else
+		{}
 	}
+
 	ast_ari_websocket_event_websocket(session, headers, &args);
+
+fin: __attribute__((unused))
+	if (response && response->response_code != 0) {
+		/* Param parsing failure */
+		/* TODO - ideally, this would return the error code to the
+		 * HTTP client; but we've already done the WebSocket
+		 * negotiation. Param parsing should happen earlier, but we
+		 * need a way to pass it through the WebSocket code to the
+		 * callback */
+		RAII_VAR(char *, msg, NULL, ast_free);
+		if (response->message) {
+			msg = ast_json_dump_string(response->message);
+		} else {
+			msg = ast_strdup("?");
+		}
+		ast_websocket_write(ws_session, AST_WEBSOCKET_OPCODE_TEXT, msg,
+			strlen(msg));
+	}
+	ast_free(args.app_parse);
+	ast_free(args.app);
 }
 
 /*! \brief REST handler for /api-docs/events.{format} */
diff --git a/res/res_ari_playback.c b/res/res_ari_playback.c
index 0dc76aff9b9ae110c142a8a6a007a82a3dba9f29..55da058a85242087776dc58a4693b412b444d7f6 100644
--- a/res/res_ari_playback.c
+++ b/res/res_ari_playback.c
@@ -41,6 +41,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_playback.h"
@@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 /*!
  * \brief Parameter parsing callback for /playback/{playbackId}.
  * \param get_params GET parameters in the HTTP request.
@@ -59,14 +62,13 @@ static void ast_ari_get_playback_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_playback_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_playback_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "playbackId") == 0) {
 			args.playback_id = (i->value);
@@ -101,6 +103,9 @@ static void ast_ari_get_playback_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /playback/{playbackId}.
@@ -113,14 +118,13 @@ static void ast_ari_stop_playback_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_stop_playback_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_stop_playback_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "playbackId") == 0) {
 			args.playback_id = (i->value);
@@ -155,6 +159,9 @@ static void ast_ari_stop_playback_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /playback/{playbackId}/control.
@@ -167,14 +174,13 @@ static void ast_ari_control_playback_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_control_playback_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_control_playback_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "operation") == 0) {
 			args.operation = (i->value);
@@ -218,6 +224,9 @@ static void ast_ari_control_playback_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 
 /*! \brief REST handler for /api-docs/playback.{format} */
diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c
index a63f37b18018891de5bd15b2ce503cf00d1acb61..01ad49a653f5dcc4de1b690fe3d7d55da65ff11c 100644
--- a/res/res_ari_recordings.c
+++ b/res/res_ari_recordings.c
@@ -41,6 +41,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_recordings.h"
@@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 /*!
  * \brief Parameter parsing callback for /recordings/stored.
  * \param get_params GET parameters in the HTTP request.
@@ -59,12 +62,12 @@ static void ast_ari_get_stored_recordings_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_stored_recordings_args args = {};
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_stored_recordings_args args = {};
 	ast_ari_get_stored_recordings(headers, &args, response);
 #if defined(AST_DEVMODE)
 	code = response->response_code;
@@ -93,6 +96,9 @@ static void ast_ari_get_stored_recordings_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/stored/{recordingName}.
@@ -105,14 +111,13 @@ static void ast_ari_get_stored_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_stored_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_stored_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -147,6 +152,9 @@ static void ast_ari_get_stored_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/stored/{recordingName}.
@@ -159,14 +167,13 @@ static void ast_ari_delete_stored_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_delete_stored_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_delete_stored_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -201,6 +208,9 @@ static void ast_ari_delete_stored_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/live.
@@ -213,12 +223,12 @@ static void ast_ari_get_live_recordings_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_live_recordings_args args = {};
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_live_recordings_args args = {};
 	ast_ari_get_live_recordings(headers, &args, response);
 #if defined(AST_DEVMODE)
 	code = response->response_code;
@@ -247,6 +257,9 @@ static void ast_ari_get_live_recordings_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/live/{recordingName}.
@@ -259,14 +272,13 @@ static void ast_ari_get_live_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_live_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_live_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -301,6 +313,9 @@ static void ast_ari_get_live_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/live/{recordingName}.
@@ -313,14 +328,13 @@ static void ast_ari_cancel_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_cancel_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_cancel_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -355,6 +369,9 @@ static void ast_ari_cancel_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/live/{recordingName}/stop.
@@ -367,14 +384,13 @@ static void ast_ari_stop_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_stop_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_stop_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -409,6 +425,9 @@ static void ast_ari_stop_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/live/{recordingName}/pause.
@@ -421,14 +440,13 @@ static void ast_ari_pause_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_pause_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_pause_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -463,6 +481,9 @@ static void ast_ari_pause_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/live/{recordingName}/unpause.
@@ -475,14 +496,13 @@ static void ast_ari_unpause_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_unpause_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_unpause_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -517,6 +537,9 @@ static void ast_ari_unpause_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/live/{recordingName}/mute.
@@ -529,14 +552,13 @@ static void ast_ari_mute_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_mute_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_mute_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -571,6 +593,9 @@ static void ast_ari_mute_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /recordings/live/{recordingName}/unmute.
@@ -583,14 +608,13 @@ static void ast_ari_unmute_recording_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_unmute_recording_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_unmute_recording_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "recordingName") == 0) {
 			args.recording_name = (i->value);
@@ -625,6 +649,9 @@ static void ast_ari_unmute_recording_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 
 /*! \brief REST handler for /api-docs/recordings.{format} */
diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c
index a7411b5bfaf007f5f21e4e63f7773987fba8ef3e..0b817c309133a74e33a8ac96840ecb1b4b854fca 100644
--- a/res/res_ari_sounds.c
+++ b/res/res_ari_sounds.c
@@ -41,6 +41,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_sounds.h"
@@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 /*!
  * \brief Parameter parsing callback for /sounds.
  * \param get_params GET parameters in the HTTP request.
@@ -59,14 +62,13 @@ static void ast_ari_get_sounds_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_sounds_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_sounds_args args = {};
-	struct ast_variable *i;
-
 	for (i = get_params; i; i = i->next) {
 		if (strcmp(i->name, "lang") == 0) {
 			args.lang = (i->value);
@@ -104,6 +106,9 @@ static void ast_ari_get_sounds_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 /*!
  * \brief Parameter parsing callback for /sounds/{soundId}.
@@ -116,14 +121,13 @@ static void ast_ari_get_stored_sound_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_get_stored_sound_args args = {};
+	struct ast_variable *i;
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
 #endif /* AST_DEVMODE */
 
-	struct ast_get_stored_sound_args args = {};
-	struct ast_variable *i;
-
 	for (i = path_vars; i; i = i->next) {
 		if (strcmp(i->name, "soundId") == 0) {
 			args.sound_id = (i->value);
@@ -158,6 +162,9 @@ static void ast_ari_get_stored_sound_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+	return;
 }
 
 /*! \brief REST handler for /api-docs/sounds.{format} */
diff --git a/rest-api-templates/ari_resource.h.mustache b/rest-api-templates/ari_resource.h.mustache
index 6396e2b73e7f148d4dd8201001f792b54848d812..8b4b0acec5405fd2e894af7ff9a8f8801a343bd7 100644
--- a/rest-api-templates/ari_resource.h.mustache
+++ b/rest-api-templates/ari_resource.h.mustache
@@ -43,10 +43,22 @@
 /*! \brief Argument struct for ast_ari_{{c_nickname}}() */
 struct ast_{{c_nickname}}_args {
 {{#parameters}}
+{{#description}}
+{{/description}}
+{{^allow_multiple}}
 {{#description}}
 	/*! \brief {{{description}}} */
 {{/description}}
 	{{c_data_type}}{{c_space}}{{c_name}};
+{{/allow_multiple}}
+{{#allow_multiple}}
+	/*! \brief Array of {{{description}}} */
+	{{c_data_type}}{{c_space}}*{{c_name}};
+	/*! \brief Length of {{c_name}} array. */
+	size_t {{c_name}}_count;
+	/*! \brief Parsing context for {{c_name}}. */
+	char *{{c_name}}_parse;
+{{/allow_multiple}}
 {{/parameters}}
 };
 {{#is_req}}
diff --git a/rest-api-templates/param_cleanup.mustache b/rest-api-templates/param_cleanup.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..46edb417ceefc98649ef9f918d16e8a164ee264f
--- /dev/null
+++ b/rest-api-templates/param_cleanup.mustache
@@ -0,0 +1,26 @@
+{{!
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+}}
+{{!
+ * Snippet for cleaning up an _args struct.
+}}
+{{#query_parameters}}
+{{#allow_multiple}}
+	ast_free(args.{{c_name}}_parse);
+	ast_free(args.{{c_name}});
+{{/allow_multiple}}
+{{/query_parameters}}
diff --git a/rest-api-templates/param_parsing.mustache b/rest-api-templates/param_parsing.mustache
index d43dcdce2676104f62bd0640449d1070b7414ef5..59c59e958e932abdb59d9d84e010f26022ca2330 100644
--- a/rest-api-templates/param_parsing.mustache
+++ b/rest-api-templates/param_parsing.mustache
@@ -18,15 +18,48 @@
 {{!
  * Snippet for decoding parameters into an _args struct.
 }}
-	struct ast_{{c_nickname}}_args args = {};
-{{#has_parameters}}
-	struct ast_variable *i;
-
 {{#has_query_parameters}}
 	for (i = get_params; i; i = i->next) {
 {{#query_parameters}}
 		if (strcmp(i->name, "{{name}}") == 0) {
+{{^allow_multiple}}
 			args.{{c_name}} = {{c_convert}}(i->value);
+{{/allow_multiple}}
+{{#allow_multiple}}
+			/* Parse comma separated list */
+			char *vals[MAX_VALS];
+			size_t j;
+
+			args.{{c_name}}_parse = ast_strdup(i->value);
+			if (!args.{{c_name}}_parse) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			args.{{c_name}}_count = ast_app_separate_args(
+				args.{{c_name}}_parse, ',', vals, ARRAY_LEN(vals));
+			if (args.{{c_name}}_count == 0) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			if (args.{{c_name}}_count >= MAX_VALS) {
+				ast_ari_response_error(response, 400,
+					"Bad Request",
+					"Too many values for {{c_name}}");
+				goto fin;
+			}
+
+			args.{{c_name}} = ast_malloc(sizeof(*args.{{c_name}}) * args.{{c_name}}_count);
+			if (!args.{{c_name}}) {
+				ast_ari_response_alloc_failed(response);
+				goto fin;
+			}
+
+			for (j = 0; j < args.{{c_name}}_count; ++j) {
+				args.{{c_name}}[j] = {{c_convert}}(vals[j]);
+			}
+{{/allow_multiple}}
 		} else
 {{/query_parameters}}
 		{}
@@ -42,4 +75,3 @@
 		{}
 	}
 {{/has_path_parameters}}
-{{/has_parameters}}
diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache
index 4f1986c7d49b660e787d75ab4d93fae694ef3a25..906d55f0dc15669338090216ce7df6da551307fc 100644
--- a/rest-api-templates/res_ari_resource.c.mustache
+++ b/rest-api-templates/res_ari_resource.c.mustache
@@ -46,6 +46,7 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/app.h"
 #include "asterisk/module.h"
 #include "asterisk/stasis_app.h"
 #include "ari/resource_{{name}}.h"
@@ -53,6 +54,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "ari/ari_model_validators.h"
 #endif
 
+#define MAX_VALS 128
+
 {{#apis}}
 {{#operations}}
 {{#is_req}}
@@ -67,6 +70,10 @@ static void ast_ari_{{c_nickname}}_cb(
 	struct ast_variable *get_params, struct ast_variable *path_vars,
 	struct ast_variable *headers, struct ast_ari_response *response)
 {
+	struct ast_{{c_nickname}}_args args = {};
+{{#has_parameters}}
+	struct ast_variable *i;
+{{/has_parameters}}
 #if defined(AST_DEVMODE)
 	int is_valid;
 	int code;
@@ -112,12 +119,21 @@ static void ast_ari_{{c_nickname}}_cb(
 			"Internal Server Error", "Response validation failed");
 	}
 #endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+{{> param_cleanup}}
+	return;
 }
 {{/is_req}}
 {{#is_websocket}}
 static void ast_ari_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session,
 	struct ast_variable *get_params, struct ast_variable *headers)
 {
+	struct ast_{{c_nickname}}_args args = {};
+{{#has_parameters}}
+	RAII_VAR(struct ast_ari_response *, response, NULL, ast_free);
+	struct ast_variable *i;
+{{/has_parameters}}
 	RAII_VAR(struct ast_websocket *, s, ws_session, ast_websocket_unref);
 	RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
 {{#has_path_parameters}}
@@ -126,7 +142,15 @@ static void ast_ari_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session,
 	 * just punt. */
 	struct ast_variable *path_vars = NULL;
 {{/has_path_parameters}}
-{{> param_parsing}}
+
+{{#has_parameters}}
+	response = ast_calloc(1, sizeof(*response));
+	if (!response) {
+		ast_log(LOG_ERROR, "Failed to create response.\n");
+		goto fin;
+	}
+{{/has_parameters}}
+
 #if defined(AST_DEVMODE)
 	session = ast_ari_websocket_session_create(ws_session,
 		ast_ari_validate_{{response_class.c_name}}_fn());
@@ -135,9 +159,31 @@ static void ast_ari_{{c_nickname}}_ws_cb(struct ast_websocket *ws_session,
 #endif
 	if (!session) {
 		ast_log(LOG_ERROR, "Failed to create ARI session\n");
-		return;
+		goto fin;
 	}
+
+{{> param_parsing}}
+
 	ast_ari_websocket_{{c_nickname}}(session, headers, &args);
+
+fin: __attribute__((unused))
+	if (response && response->response_code != 0) {
+		/* Param parsing failure */
+		/* TODO - ideally, this would return the error code to the
+		 * HTTP client; but we've already done the WebSocket
+		 * negotiation. Param parsing should happen earlier, but we
+		 * need a way to pass it through the WebSocket code to the
+		 * callback */
+		RAII_VAR(char *, msg, NULL, ast_free);
+		if (response->message) {
+			msg = ast_json_dump_string(response->message);
+		} else {
+			msg = ast_strdup("?");
+		}
+		ast_websocket_write(ws_session, AST_WEBSOCKET_OPCODE_TEXT, msg,
+			strlen(msg));
+	}
+{{> param_cleanup}}
 }
 {{/is_websocket}}
 {{/operations}}
diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json
index 7b3c4a37b9140ea68911dadb02144a7dac020229..57954dd277b74f02ad19881795fc7fa15a09a640 100644
--- a/rest-api/api-docs/bridges.json
+++ b/rest-api/api-docs/bridges.json
@@ -114,7 +114,7 @@
 						},
 						{
 							"name": "channel",
-							"description": "Channel's id",
+							"description": "Ids of channels to add to bridge",
 							"paramType": "query",
 							"required": true,
 							"allowMultiple": true,
@@ -158,7 +158,7 @@
 						},
 						{
 							"name": "channel",
-							"description": "Channel's id",
+							"description": "Ids of channels to remove from bridge",
 							"paramType": "query",
 							"required": true,
 							"allowMultiple": true,
@@ -277,7 +277,7 @@
 							"description": "Format to encode audio in",
 							"paramType": "query",
 							"required": true,
-							"allowMultiple": true,
+							"allowMultiple": false,
 							"dataType": "string"
 						},
 						{
@@ -389,7 +389,7 @@
 				},
 				"channels": {
 					"type": "List[string]",
-					"description": "Id's of channels participating in this bridge",
+					"description": "Ids of channels participating in this bridge",
 					"required": true
 				}
 			}
diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json
index e54b02772945d505fc8589e8a743fa3a804af5ca..41b6cc08c61fc42218b745a0e155e174f1a2dfd6 100644
--- a/rest-api/api-docs/channels.json
+++ b/rest-api/api-docs/channels.json
@@ -634,7 +634,7 @@
 							"description": "Format to encode audio in",
 							"paramType": "query",
 							"required": true,
-							"allowMultiple": true,
+							"allowMultiple": false,
 							"dataType": "string"
 						},
 						{
diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json
index 519bb7ae79e60f81867bd25551907f0d7bb48498..a2ac0b3d03143d39e8345473f043c2bd26a0c034 100644
--- a/rest-api/api-docs/events.json
+++ b/rest-api/api-docs/events.json
@@ -21,7 +21,7 @@
 					"parameters": [
 						{
 							"name": "app",
-							"description": "Comma seperated list of applications to subscribe to.",
+							"description": "Applications to subscribe to.",
 							"paramType": "query",
 							"required": true,
 							"allowMultiple": true,
diff --git a/rest-api/api-docs/sounds.json b/rest-api/api-docs/sounds.json
index 103738c45ae6d614ec06c245d5c10d391603fcc4..fe0b09fd49bf30c336e8c3dc5ed7f68adcdb022e 100644
--- a/rest-api/api-docs/sounds.json
+++ b/rest-api/api-docs/sounds.json
@@ -19,12 +19,14 @@
 					"parameters": [
 						{
 							"name": "lang",
+							"description": "Lookup sound for a specific language.",
 							"paramType": "query",
 							"dataType": "string",
 							"required": false
 						},
 						{
 							"name": "format",
+							"description": "Lookup sound in a specific format.",
 							"paramType": "query",
 							"dataType": "string",
 							"required": false,