diff --git a/SVSim.EmulatedEntrypoint/Controllers/DownloadTimeController.cs b/SVSim.EmulatedEntrypoint/Controllers/DownloadTimeController.cs
new file mode 100644
index 0000000..02ce447
--- /dev/null
+++ b/SVSim.EmulatedEntrypoint/Controllers/DownloadTimeController.cs
@@ -0,0 +1,36 @@
+using Microsoft.AspNetCore.Mvc;
+using SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
+
+namespace SVSim.EmulatedEntrypoint.Controllers;
+
+///
+/// /download_time/* — asset-download timing telemetry. The client fires
+/// POST /download_time/start right before kicking off an Akamai asset bundle
+/// download (Wizard/DownloadStartTask.cs) and POST /download_time/end when
+/// it completes (Wizard/DownloadFinishTask.cs). Both are pure telemetry from our
+/// perspective — we don't track download timings — but the client surfaces an HTTP error
+/// dialog if either 404s, so we ack with empty data: {} bodies.
+///
+/// Explicit because the base controller token would
+/// resolve to /downloadtime, missing the underscore.
+///
+[Route("download_time")]
+public class DownloadTimeController : SVSimController
+{
+ ///
+ /// Spec: docs/api-spec/endpoints/post-login/download_time-start.md. The client's
+ /// DownloadStartTask.Parse reads an optional image_type string
+ /// ("card" → CardDetail loading-screen art, "still" → StoryDetail, anything
+ /// else → default). We omit it; the client falls through to the default art.
+ ///
+ [HttpPost("start")]
+ public IActionResult Start([FromBody] BaseRequest request) => Ok(new { });
+
+ ///
+ /// Spec: docs/api-spec/endpoints/post-login/download_time-end.md. The client's
+ /// DownloadFinishTask doesn't override Parse at all — only result_code
+ /// matters. Empty data is the documented minimum-viable response.
+ ///
+ [HttpPost("end")]
+ public IActionResult End([FromBody] BaseRequest request) => Ok(new { });
+}
diff --git a/SVSim.UnitTests/Controllers/DownloadTimeControllerTests.cs b/SVSim.UnitTests/Controllers/DownloadTimeControllerTests.cs
new file mode 100644
index 0000000..1cf922d
--- /dev/null
+++ b/SVSim.UnitTests/Controllers/DownloadTimeControllerTests.cs
@@ -0,0 +1,33 @@
+using System.Net;
+using System.Text;
+using System.Text.Json;
+using NUnit.Framework;
+using SVSim.UnitTests.Infrastructure;
+
+namespace SVSim.UnitTests.Controllers;
+
+public class DownloadTimeControllerTests
+{
+ [TestCase("/download_time/start")]
+ [TestCase("/download_time/end")]
+ public async Task Returns_200_with_empty_data_object(string path)
+ {
+ using var factory = new SVSimTestFactory();
+ long viewerId = await factory.SeedViewerAsync();
+ using var client = factory.CreateAuthenticatedClient(viewerId);
+
+ var requestJson = """{"viewer_id":"0","steam_id":0,"steam_session_ticket":""}""";
+
+ var response = await client.PostAsync(path,
+ new StringContent(requestJson, Encoding.UTF8, "application/json"));
+
+ Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK),
+ await response.Content.ReadAsStringAsync());
+
+ using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
+ Assert.That(doc.RootElement.ValueKind, Is.EqualTo(JsonValueKind.Object));
+ Assert.That(doc.RootElement.EnumerateObject().Count(), Is.EqualTo(0),
+ "Spec calls for empty `data: {}` — DownloadStartTask's optional image_type stays " +
+ "absent, DownloadFinishTask doesn't read data at all.");
+ }
+}