diff --git a/services/reports/src/database/item.rs b/services/reports/src/database/item.rs
--- a/services/reports/src/database/item.rs
+++ b/services/reports/src/database/item.rs
@@ -213,6 +213,19 @@
   ) -> Result<(), BlobServiceError> {
     todo!()
   }
+
+  /// Fetches report content bytes
+  pub async fn fetch_bytes(
+    self,
+    blob_client: &BlobServiceClient,
+  ) -> Result<Vec<u8>, BlobServiceError> {
+    match self {
+      ReportContent::Database(data) => Ok(data),
+      ReportContent::Blob(BlobInfo { blob_hash, .. }) => {
+        todo!()
+      }
+    }
+  }
 }
 
 // DB conversions for report types
diff --git a/services/reports/src/http/handlers.rs b/services/reports/src/http/handlers.rs
--- a/services/reports/src/http/handlers.rs
+++ b/services/reports/src/http/handlers.rs
@@ -1,6 +1,8 @@
-use actix_web::{post, web, HttpResponse};
+use actix_web::{get, post, web, HttpResponse};
 use serde::Deserialize;
 
+use super::NotFoundHandler;
+
 use crate::report_types::ReportInput;
 use crate::service::ReportsService;
 
@@ -21,7 +23,7 @@
   }
 }
 
-#[post("/reports")]
+#[post("")]
 async fn post_reports(
   payload: web::Json<PostReportsPayload>,
   service: ReportsService,
@@ -33,3 +35,17 @@
   let response = HttpResponse::Created().json(json!({ "reportIDs": ids }));
   Ok(response)
 }
+
+#[get("/{report_id}")]
+async fn get_single_report(
+  path: web::Path<String>,
+  service: ReportsService,
+) -> actix_web::Result<HttpResponse> {
+  let report_id = path.into_inner();
+  let report = service
+    .get_report(report_id.into())
+    .await?
+    .unwrap_or_404()?;
+  let response = HttpResponse::Ok().json(report);
+  Ok(response)
+}
diff --git a/services/reports/src/http/mod.rs b/services/reports/src/http/mod.rs
--- a/services/reports/src/http/mod.rs
+++ b/services/reports/src/http/mod.rs
@@ -1,6 +1,6 @@
 use actix_web::error::{
-  ErrorBadRequest, ErrorInternalServerError, ErrorServiceUnavailable,
-  ErrorUnsupportedMediaType,
+  ErrorBadRequest, ErrorInternalServerError, ErrorNotFound,
+  ErrorServiceUnavailable, ErrorUnsupportedMediaType,
 };
 use actix_web::{web, App, HttpResponse, HttpServer, ResponseError};
 use anyhow::Result;
@@ -34,7 +34,11 @@
       .wrap(cors_config(CONFIG.is_dev()))
       // Health endpoint for load balancers checks
       .route("/health", web::get().to(HttpResponse::Ok))
-      .service(handlers::post_reports)
+      .service(
+        web::scope("/reports")
+          .service(handlers::post_reports)
+          .service(handlers::get_single_report),
+      )
   })
   .bind(("0.0.0.0", CONFIG.http_port))?
   .run()
@@ -100,3 +104,14 @@
       .status_code()
   }
 }
+
+trait NotFoundHandler<T> {
+  /// Returns `Ok(T)` if `self` is `Some(T)`,
+  /// otherwise returns a `404 Not Found` error.
+  fn unwrap_or_404(self) -> actix_web::Result<T>;
+}
+impl<T> NotFoundHandler<T> for Option<T> {
+  fn unwrap_or_404(self) -> actix_web::Result<T> {
+    self.ok_or_else(|| ErrorNotFound("not found"))
+  }
+}
diff --git a/services/reports/src/service.rs b/services/reports/src/service.rs
--- a/services/reports/src/service.rs
+++ b/services/reports/src/service.rs
@@ -10,7 +10,7 @@
 
 use crate::{
   database::{client::DatabaseClient, item::ReportItem},
-  report_types::{ReportID, ReportInput},
+  report_types::{ReportID, ReportInput, ReportOutput},
 };
 
 #[derive(Debug, Display, Error, From)]
@@ -94,6 +94,37 @@
     self.db.save_reports(items).await?;
     Ok(ids)
   }
+
+  pub async fn get_report(
+    &self,
+    report_id: ReportID,
+  ) -> ServiceResult<Option<ReportOutput>> {
+    let Some(report_item) = self.db.get_report(&report_id).await? else {
+      return Ok(None);
+    };
+    let ReportItem {
+      user_id,
+      report_type,
+      platform,
+      creation_time,
+      content,
+      ..
+    } = report_item;
+
+    let report_data = content.fetch_bytes(&self.blob_client).await?;
+    let report_json = serde_json::from_slice(report_data.as_slice())
+      .map_err(ReportsServiceError::SerdeError)?;
+
+    let output = ReportOutput {
+      id: report_id,
+      user_id,
+      platform,
+      report_type,
+      creation_time,
+      content: report_json,
+    };
+    Ok(Some(output))
+  }
 }
 
 impl FromRequest for ReportsService {