diff --git a/services/identity/src/websockets/mod.rs b/services/identity/src/websockets/mod.rs
--- a/services/identity/src/websockets/mod.rs
+++ b/services/identity/src/websockets/mod.rs
@@ -3,7 +3,7 @@
 use std::pin::Pin;
 use std::sync::Arc;
 
-use elastic::client::responses::SearchResponse;
+use elastic::client::responses::SearchResponse as ElasticSearchResponse;
 use futures::lock::Mutex;
 use futures_util::{SinkExt, StreamExt};
 use hyper::{Body, Request, Response, StatusCode};
@@ -11,7 +11,8 @@
 use hyper_tungstenite::HyperWebsocket;
 use identity_search_messages::{
   ConnectionInitializationResponse, ConnectionInitializationStatus, Heartbeat,
-  IdentitySearchMethod, IdentitySearchResult, IdentitySearchUser, Messages,
+  IdentitySearchFailure, IdentitySearchMethod, IdentitySearchResponse,
+  IdentitySearchResult, IdentitySearchUser, Messages,
 };
 use serde::{Deserialize, Serialize};
 use tokio::net::TcpListener;
@@ -142,12 +143,13 @@
 }
 
 async fn handle_prefix_search(
-  prefix: &str,
-) -> Result<String, errors::WebsocketError> {
+  request_id: &str,
+  prefix_request: identity_search_messages::IdentitySearchPrefix,
+) -> Result<IdentitySearchResult, errors::WebsocketError> {
   let prefix_query = Query {
     query: Prefix {
       prefix: Username {
-        username: prefix.trim().to_string(),
+        username: prefix_request.prefix.trim().to_string(),
       },
     },
   };
@@ -157,14 +159,16 @@
 
   let search_response = send_search_request(&opensearch_url, prefix_query)
     .await?
-    .json::<SearchResponse<IdentitySearchUser>>()
+    .json::<ElasticSearchResponse<IdentitySearchUser>>()
     .await?;
 
   let usernames: Vec<IdentitySearchUser> =
     search_response.into_documents().collect();
 
-  let search_result =
-    serde_json::to_string(&IdentitySearchResult { hits: usernames })?;
+  let search_result = IdentitySearchResult {
+    id: request_id.to_string(),
+    hits: usernames,
+  };
 
   Ok(search_result)
 }
@@ -182,14 +186,24 @@
       debug!("Received heartbeat");
       Ok(())
     }
-    Messages::IdentitySearchQuery(search_request) => {
-      let search_result = match search_request.search_method {
-        IdentitySearchMethod::IdentitySearchPrefix(prefix_request) => {
-          handle_prefix_search(&prefix_request.prefix).await
+    Messages::IdentitySearchQuery(search_query) => {
+      let handler_result = match search_query.search_method {
+        IdentitySearchMethod::IdentitySearchPrefix(prefix_query) => {
+          handle_prefix_search(&search_query.id, prefix_query).await
         }
-      }?;
+      };
+
+      let search_response = match handler_result {
+        Ok(search_result) => IdentitySearchResponse::Success(search_result),
+        Err(e) => IdentitySearchResponse::Error(IdentitySearchFailure {
+          id: search_query.id,
+          error: e.to_string(),
+        }),
+      };
+
+      let serialized_message = serde_json::to_string(&search_response)?;
 
-      send_message(Message::Text(search_result), outgoing.clone()).await;
+      send_message(Message::Text(serialized_message), outgoing.clone()).await;
 
       Ok(())
     }
diff --git a/shared/identity_search_messages/src/messages/mod.rs b/shared/identity_search_messages/src/messages/mod.rs
--- a/shared/identity_search_messages/src/messages/mod.rs
+++ b/shared/identity_search_messages/src/messages/mod.rs
@@ -2,11 +2,11 @@
 
 pub mod auth_messages;
 pub mod search_query;
-pub mod search_result;
+pub mod search_response;
 
 pub use auth_messages::*;
 pub use search_query::*;
-pub use search_result::*;
+pub use search_response::*;
 
 use serde::{Deserialize, Serialize};
 pub use websocket_messages::{
@@ -20,5 +20,5 @@
   IdentitySearchQuery(IdentitySearchQuery),
   Heartbeat(Heartbeat),
   ConnectionInitializationResponse(ConnectionInitializationResponse),
-  IdentitySearchResult(IdentitySearchResult),
+  IdentitySearchResponse(IdentitySearchResponse),
 }
diff --git a/shared/identity_search_messages/src/messages/search_query.rs b/shared/identity_search_messages/src/messages/search_query.rs
--- a/shared/identity_search_messages/src/messages/search_query.rs
+++ b/shared/identity_search_messages/src/messages/search_query.rs
@@ -16,5 +16,6 @@
 #[derive(Debug, Serialize, Deserialize)]
 #[serde(tag = "type", rename_all = "camelCase")]
 pub struct IdentitySearchQuery {
+  pub id: String,
   pub search_method: IdentitySearchMethod,
 }
diff --git a/shared/identity_search_messages/src/messages/search_result.rs b/shared/identity_search_messages/src/messages/search_response.rs
rename from shared/identity_search_messages/src/messages/search_result.rs
rename to shared/identity_search_messages/src/messages/search_response.rs
--- a/shared/identity_search_messages/src/messages/search_result.rs
+++ b/shared/identity_search_messages/src/messages/search_response.rs
@@ -2,6 +2,12 @@
 
 use serde::{Deserialize, Serialize};
 
+#[derive(Debug, Serialize, Deserialize)]
+pub struct IdentitySearchFailure {
+  pub id: String,
+  pub error: String,
+}
+
 #[derive(Debug, Serialize, Deserialize)]
 pub struct IdentitySearchUser {
   #[serde(rename = "userID")]
@@ -10,7 +16,14 @@
 }
 
 #[derive(Debug, Serialize, Deserialize)]
-#[serde(tag = "type")]
 pub struct IdentitySearchResult {
+  pub id: String,
   pub hits: Vec<IdentitySearchUser>,
 }
+
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(tag = "type", content = "data")]
+pub enum IdentitySearchResponse {
+  Success(IdentitySearchResult),
+  Error(IdentitySearchFailure),
+}