diff --git a/CMakeLists.txt b/CMakeLists.txt
index 752019af..1f9050ad 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,6 +18,7 @@ set(obs-websocket_SOURCES
 	Utils.cpp)
 
 set(obs-websocket_HEADERS
+	obs-websocket.h
 	WSServer.h
 	WSRequestHandler.h
 	WSEvents.h
diff --git a/Utils.cpp b/Utils.cpp
index 4658125d..d545231a 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -1,30 +1,63 @@
 #include "Utils.h"
 
-obs_data_array_t* Utils::GetSceneItems(obs_source_t *source) {
-	obs_data_array *items = obs_data_array_create();
-	obs_scene *scene = obs_scene_from_source(source);
+bool enum_scene_items(obs_scene_t *scene, obs_sceneitem_t *currentItem, void *param) {
+	obs_data_array_t *data = static_cast<obs_data_array *>(param);
+	obs_data_array_push_back(data, Utils::GetSceneItemData(currentItem));
+	return true;
+}
 
-	/*obs_scene_item *currentItem = scene->first_item;
-	while (currentItem != NULL) {
-		obs_data_array_push_back(items, GetSceneItemData(currentItem));
-		currentItem = currentItem->next;
-	}*/
+obs_data_array_t* Utils::GetSceneItems(obs_source_t *source) {
+	obs_data_array_t *items = obs_data_array_create();
+	obs_scene_t *scene = obs_scene_from_source(source);
+
+	obs_scene_enum_items(scene, enum_scene_items, items);
 
 	return items;
 }
 
-obs_data_t* Utils::GetSceneItemData(obs_scene_item *item) {
+obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t *item) {
 	if (!item) {
 		return NULL;
 	}
 
+	vec2 pos;
+	obs_sceneitem_get_pos(item, &pos);
+
+	vec2 bounds;
+	obs_sceneitem_get_bounds(item, &bounds);
+
 	obs_data_t *data = obs_data_create();
-	/*obs_data_set_string(data, "name", obs_source_get_name(item->source));
-	obs_data_set_double(data, "x", item->pos.x);
-	obs_data_set_double(data, "y", item->pos.y);
-	obs_data_set_double(data, "cx", item->bounds.x);
-	obs_data_set_double(data, "cy", item->bounds.y);
-	obs_data_set_bool(data, "render", item->visible);*/
+	obs_data_set_string(data, "name", obs_source_get_name(obs_sceneitem_get_source(item)));
+	obs_data_set_string(data, "type", obs_source_get_id(obs_sceneitem_get_source(item)));
+	obs_data_set_double(data, "volume", obs_source_get_volume(obs_sceneitem_get_source(item)));
+	obs_data_set_double(data, "x", pos.x);
+	obs_data_set_double(data, "y", pos.y);
+	obs_data_set_double(data, "cx", bounds.x);
+	obs_data_set_double(data, "cy", bounds.y);
+	obs_data_set_bool(data, "render", obs_sceneitem_visible(item));
 
 	return data;
+}
+
+obs_data_array_t* Utils::GetScenes() {
+	obs_frontend_source_list sceneList = {};
+	obs_frontend_get_scenes(&sceneList);
+
+	obs_data_array_t* scenes = obs_data_array_create();
+	for (size_t i = 0; i < (&sceneList)->sources.num; i++) {
+		obs_source_t* scene = (&sceneList)->sources.array[i];
+		obs_data_array_push_back(scenes, GetSceneData(scene));
+	}
+
+	obs_frontend_source_list_free(&sceneList);
+
+	return scenes;
+}
+
+obs_data_t* Utils::GetSceneData(obs_source *source) {
+	obs_data_t* sceneData = obs_data_create();
+	obs_data_set_string(sceneData, "name", obs_source_get_name(source));
+	obs_data_set_array(sceneData, "sources", GetSceneItems(source));
+	
+	return sceneData;
 }
\ No newline at end of file
diff --git a/Utils.h b/Utils.h
index 27ac7ae8..7c340f13 100644
--- a/Utils.h
+++ b/Utils.h
@@ -2,12 +2,16 @@
 #define UTILS_H
 
 #include <obs-module.h>
+#include <obs-frontend-api.h>
 
 class Utils
 {
 	public:
 		static obs_data_array_t* GetSceneItems(obs_source_t* source);
 		static obs_data_t* GetSceneItemData(obs_scene_item *item);
+
+		static obs_data_array_t* GetScenes();
+		static obs_data_t* GetSceneData(obs_source *source);
 };
 
 #endif // UTILS_H
\ No newline at end of file
diff --git a/WSEvents.cpp b/WSEvents.cpp
index 3fab24a9..f43dc2ab 100644
--- a/WSEvents.cpp
+++ b/WSEvents.cpp
@@ -5,7 +5,7 @@ WSEvents::WSEvents(WSServer *server) {
 	obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this);
 
 	QTimer *statusTimer = new QTimer();
-	connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus));
+	connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus()));
 	statusTimer->start(1000);
 }
 
@@ -17,9 +17,14 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private
 {
 	WSEvents *owner = static_cast<WSEvents *>(private_data);
 
+	// TODO : implement SourceChanged, SourceOrderChanged and RepopulateSources
+
 	if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED) {
 		owner->OnSceneChange();
 	}
+	else if (event == OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED) {
+		owner->OnSceneListChange();
+	}
 	else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTING) {
 		owner->OnStreamStarting();
 	}
@@ -44,6 +49,9 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private
 	else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPED) {
 		owner->OnRecordingStopped();
 	}
+	else if (event == OBS_FRONTEND_EVENT_EXIT) {
+		owner->OnExit();
+	}
 }
 
 void WSEvents::broadcastUpdate(const char *updateType, obs_data_t *additionalFields = NULL) {
@@ -77,6 +85,10 @@ void WSEvents::OnSceneChange() {
 	obs_source_release(source);
 }
 
+void WSEvents::OnSceneListChange() {
+	broadcastUpdate("ScenesChanged");
+}
+
 void WSEvents::OnStreamStarting() {
 	// Implements an existing update type from bilhamil's OBS Remote
 	obs_data_t *data = obs_data_create();
@@ -130,22 +142,21 @@ void WSEvents::OnRecordingStopped() {
 	broadcastUpdate("RecordingStopped");
 }
 
-// TODO : Add a timer to trigger StreamStatus
-void WSEvents::StreamStatus() {
-	blog(LOG_INFO, "top StreamStatus");
+void WSEvents::OnExit() {
+	// New update type specific to OBS Studio
+	broadcastUpdate("Exiting");
+}
 
+void WSEvents::StreamStatus() {
 	bool streamingActive = obs_frontend_streaming_active();
 	bool recordingActive = obs_frontend_recording_active();
 
 	obs_output_t *streamOutput = obs_frontend_get_streaming_output();
 
-	if (!streamOutput) {
-		blog(LOG_INFO, "not this time. no stream output running.");
+	if (!streamOutput || !streamingActive || !recordingActive) {
 		return;
 	}
 
-	uint64_t bytesPerSec = 0;
-
 	uint64_t bytesSent = obs_output_get_total_bytes(streamOutput);
 	uint64_t bytesSentTime = os_gettime_ns();
 
@@ -160,22 +171,22 @@ void WSEvents::StreamStatus() {
 	double timePassed = double(bytesSentTime - _lastBytesSentTime) / 1000000000.0;
 
 	uint64_t bitsPerSec = bitsBetween / timePassed;
-	bytesPerSec = bitsPerSec / 8;
+	uint64_t bytesPerSec = bitsPerSec / 8;
 
-	uint64_t totalStreamTime = (os_gettime_ns() - _streamStartTime); // TODO : convert to seconds
-	
-	uint64_t droppedFrames = obs_output_get_frames_dropped(streamOutput);
-	uint64_t totalFrames = obs_output_get_total_frames(streamOutput);
+	_lastBytesSent = bytesSent;
+	_lastBytesSentTime = bytesSentTime;
+
+	uint64_t totalStreamTime = (os_gettime_ns() - _streamStartTime) / 1000000000;
 
 	obs_data_t *data = obs_data_create();
 	obs_data_set_bool(data, "streaming", streamingActive);
-	obs_data_set_bool(data, "recording", recordingActive); // New in OBS Studio
+	obs_data_set_bool(data, "recording", recordingActive);
 	obs_data_set_bool(data, "preview-only", false); // Retrocompat with OBSRemote
-	obs_data_set_int(data, "bytes-per-sec", bytesPerSec);
-	obs_data_set_double(data, "strain", 0.0); // TODO
+	obs_data_set_int(data, "bytes-per-sec", bytesPerSec); // BUG : Computation seems buggy
+	obs_data_set_double(data, "strain", 0.0); // dafuq is strain
 	obs_data_set_int(data, "total-stream-time", totalStreamTime);
-	obs_data_set_int(data, "num-total-frames", totalFrames);
-	obs_data_set_int(data, "num-dropped-frames", droppedFrames);
+	obs_data_set_int(data, "num-total-frames", obs_output_get_total_frames(streamOutput));
+	obs_data_set_int(data, "num-dropped-frames", obs_output_get_frames_dropped(streamOutput));
 	obs_data_set_double(data, "fps", obs_get_active_fps());
 
 	broadcastUpdate("StreamStatus", data);
diff --git a/WSEvents.h b/WSEvents.h
index d843877d..18192c5c 100644
--- a/WSEvents.h
+++ b/WSEvents.h
@@ -27,6 +27,7 @@ class WSEvents : public QObject
 		void broadcastUpdate(const char *updateType, obs_data_t *additionalFields);
 
 		void OnSceneChange();
+		void OnSceneListChange();
 
 		void OnStreamStarting();
 		void OnStreamStarted();
@@ -37,6 +38,8 @@ class WSEvents : public QObject
 		void OnRecordingStarted();
 		void OnRecordingStopping();
 		void OnRecordingStopped();
+
+		void OnExit();
 };
 
 #endif // WSEVENTS_H
\ No newline at end of file
diff --git a/WSRequestHandler.cpp b/WSRequestHandler.cpp
index 0a353ce2..aa05d0c4 100644
--- a/WSRequestHandler.cpp
+++ b/WSRequestHandler.cpp
@@ -1,11 +1,17 @@
 #include "WSRequestHandler.h"
+#include "obs-websocket.h"
+#include "Utils.h"
 
 WSRequestHandler::WSRequestHandler(QWebSocket *client) {
 	_client = client;
 
+	messageMap["GetVersion"] = WSRequestHandler::HandleGetVersion;
+	messageMap["GetAuthRequired"] = WSRequestHandler::HandleGetAuthRequired;
+	messageMap["Authenticate"] = WSRequestHandler::HandleAuthenticate;
+
 	messageMap["SetCurrentScene"] = WSRequestHandler::HandleSetCurrentScene;
 	messageMap["GetCurrentScene"] = WSRequestHandler::HandleGetCurrentScene;
-	messageMap["GetSceneList"] = WSRequestHandler::ErrNotImplemented;
+	messageMap["GetSceneList"] = WSRequestHandler::HandleGetSceneList;
 	messageMap["SetSourceOrder"] = WSRequestHandler::ErrNotImplemented;
 	messageMap["SetSourceRender"] = WSRequestHandler::ErrNotImplemented;
 	messageMap["SetSceneItemPositionAndSize"] = WSRequestHandler::ErrNotImplemented;
@@ -69,6 +75,41 @@ void WSRequestHandler::SendErrorResponse(const char *errorMessage) {
 	obs_data_release(response);
 }
 
+void WSRequestHandler::HandleGetVersion(WSRequestHandler *owner) {
+	obs_data_t *data = obs_data_create();
+	obs_data_set_double(data, "version", OBS_WEBSOCKET_VERSION);
+
+	owner->SendOKResponse(data);
+
+	obs_data_release(data);
+}
+
+void WSRequestHandler::HandleGetAuthRequired(WSRequestHandler *owner) {
+	bool authRequired = false; // Auth isn't implemented yet
+	
+	obs_data_t *data = obs_data_create();
+	obs_data_set_bool(data, "authRequired", authRequired);
+	if (authRequired) {
+		// Just here for protocol doc
+		obs_data_set_string(data, "challenge", "");
+		obs_data_set_string(data, "salt", "");
+	}
+
+	owner->SendOKResponse(data);
+
+	obs_data_release(data);
+}
+
+void WSRequestHandler::HandleAuthenticate(WSRequestHandler *owner) {
+	const char *auth = obs_data_get_string(owner->_requestData, "auth");
+	if (!auth) {
+		owner->SendErrorResponse("auth not specified!");
+		return;
+	}
+
+	owner->SendOKResponse();
+}
+
 void WSRequestHandler::HandleSetCurrentScene(WSRequestHandler *owner) {
 	const char *sceneName = obs_data_get_string(owner->_requestData, "scene-name");
 	obs_source_t *source = obs_get_source_by_name(sceneName);
@@ -78,7 +119,6 @@ void WSRequestHandler::HandleSetCurrentScene(WSRequestHandler *owner) {
 		owner->SendOKResponse();
 	}
 	else {
-		blog(LOG_ERROR, "[obs-websockets] requested scene '%s' doesn't exist !", sceneName);
 		owner->SendErrorResponse("requested scene does not exist");
 	}
 
@@ -98,6 +138,16 @@ void WSRequestHandler::HandleGetCurrentScene(WSRequestHandler *owner) {
 	obs_source_release(source);
 }
 
+void WSRequestHandler::HandleGetSceneList(WSRequestHandler *owner) {
+	obs_data_t *data = obs_data_create();
+	obs_data_set_string(data, "current-scene", obs_source_get_name(obs_frontend_get_current_scene()));
+	obs_data_set_array(data, "scenes", Utils::GetScenes());
+
+	owner->SendOKResponse(data);
+
+	obs_data_release(data);
+}
+
 void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler *owner) {
 	obs_data_t *data = obs_data_create();
 	obs_data_set_bool(data, "streaming", obs_frontend_streaming_active());
diff --git a/WSRequestHandler.h b/WSRequestHandler.h
index c7785c72..5207837f 100644
--- a/WSRequestHandler.h
+++ b/WSRequestHandler.h
@@ -4,8 +4,6 @@
 #include <map>
 #include <QtWebSockets/QWebSocket>
 #include <obs-frontend-api.h>
-#include "Utils.h"
-#include "WSServer.h"
 
 class WSRequestHandler
 {
@@ -24,10 +22,14 @@ class WSRequestHandler
 
 		void SendOKResponse(obs_data_t *additionalFields = NULL);
 		void SendErrorResponse(const char *errorMessage);
-		
 		static void ErrNotImplemented(WSRequestHandler *owner);
+		
+		static void HandleGetVersion(WSRequestHandler *owner);
+		static void HandleGetAuthRequired(WSRequestHandler *owner);
+		static void HandleAuthenticate(WSRequestHandler *owner);
 		static void HandleSetCurrentScene(WSRequestHandler *owner);
 		static void HandleGetCurrentScene(WSRequestHandler *owner);
+		static void HandleGetSceneList(WSRequestHandler *owner);
 		static void HandleGetStreamingStatus(WSRequestHandler *owner);
 		static void HandleStartStopStreaming(WSRequestHandler *owner);
 		static void HandleStartStopRecording(WSRequestHandler *owner);