diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp
index 2fa648937..685009424 100644
--- a/src/core/hle/service/boss/boss.cpp
+++ b/src/core/hle/service/boss/boss.cpp
@@ -631,34 +631,51 @@ void Module::Interface::DeleteNsData(Kernel::HLERequestContext& ctx) {
 
 void Module::Interface::GetNsDataHeaderInfo(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx);
-    const u32 ns_data_id = rp.Pop<u32>();
-    const u8 type = rp.Pop<u8>();
-    const u32 size = rp.Pop<u32>();
+    const auto ns_data_id = rp.Pop<u32>();
+    const auto type = rp.PopEnum<NsDataHeaderInfoType>();
+    const auto size = rp.Pop<u32>();
     auto& buffer = rp.PopMappedBuffer();
 
+    const auto online_service = GetSessionService(ctx);
+    if (online_service == nullptr) {
+        return;
+    }
+    const auto result = online_service->GetNsDataHeaderInfo(ns_data_id, type, size, buffer);
+
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
-    rb.Push(RESULT_SUCCESS);
+    rb.Push(result);
     rb.PushMappedBuffer(buffer);
 
-    LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010x}, type={:#04x}, size={:#010x}",
-                ns_data_id, type, size);
+    LOG_DEBUG(Service_BOSS, "called, ns_data_id={:#010x}, type={:#04x}, size={:#010x}", ns_data_id,
+              type, size);
 }
 
 void Module::Interface::ReadNsData(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx);
-    const u32 ns_data_id = rp.Pop<u32>();
-    const u64 offset = rp.Pop<u64>();
-    const u32 size = rp.Pop<u32>();
+    const auto ns_data_id = rp.Pop<u32>();
+    const auto offset = rp.Pop<u64>();
+    const auto size = rp.Pop<u32>();
     auto& buffer = rp.PopMappedBuffer();
 
-    IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
-    rb.Push(RESULT_SUCCESS);
-    rb.Push<u32>(size); /// Should be actual read size
-    rb.Push<u32>(0);    /// unknown
-    rb.PushMappedBuffer(buffer);
+    const auto online_service = GetSessionService(ctx);
+    if (online_service == nullptr) {
+        return;
+    }
+    const auto result = online_service->ReadNsData(ns_data_id, offset, size, buffer);
 
-    LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010x}, offset={:#018x}, size={:#010x}",
-                ns_data_id, offset, size);
+    if (result.Succeeded()) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
+        rb.Push(result.Code());
+        rb.Push<u32>(static_cast<u32>(result.Unwrap()));
+        rb.Push<u32>(0); /// unknown
+        rb.PushMappedBuffer(buffer);
+    } else {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(result.Code());
+    }
+
+    LOG_DEBUG(Service_BOSS, "called, ns_data_id={:#010x}, offset={:#018x}, size={:#010x}",
+              ns_data_id, offset, size);
 }
 
 void Module::Interface::SetNsDataAdditionalInfo(Kernel::HLERequestContext& ctx) {
@@ -710,14 +727,27 @@ void Module::Interface::GetNsDataNewFlag(Kernel::HLERequestContext& ctx) {
 
 void Module::Interface::GetNsDataLastUpdate(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx);
-    const u32 unk_param1 = rp.Pop<u32>();
+    const u32 ns_data_id = rp.Pop<u32>();
+
+    const auto online_service = GetSessionService(ctx);
+    if (online_service == nullptr) {
+        return;
+    }
+
+    const auto entry = online_service->GetNsDataEntryFromId(ns_data_id);
+    if (!entry.has_value()) {
+        // TODO: Proper error code.
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(RESULT_UNKNOWN);
+        return;
+    }
 
     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
     rb.Push(RESULT_SUCCESS);
-    rb.Push<u32>(0); // stub 0 (32bit value)
-    rb.Push<u32>(0); // stub 0 (32bit value)
+    rb.Push<u32>(0);
+    rb.Push<u32>(entry->header.download_date); // return the download date from the ns data
 
-    LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010x}", unk_param1);
+    LOG_DEBUG(Service_BOSS, "called, ns_data_id={:#010X}", ns_data_id);
 }
 
 void Module::Interface::GetErrorCode(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/boss/online_service.cpp b/src/core/hle/service/boss/online_service.cpp
index 6a1497521..10f1ba058 100644
--- a/src/core/hle/service/boss/online_service.cpp
+++ b/src/core/hle/service/boss/online_service.cpp
@@ -73,12 +73,14 @@ ResultCode OnlineService::InitializeSession(u64 init_program_id) {
         auto create_archive_result = systemsavedata_factory.Open(archive_path, 0);
         if (!create_archive_result.Succeeded()) {
             LOG_ERROR(Service_BOSS, "Could not open BOSS savedata");
-            return ResultCode(1);
+            // TODO: Proper error code.
+            return RESULT_UNKNOWN;
         }
         boss_system_save_data_archive = std::move(create_archive_result).Unwrap();
     } else {
         LOG_ERROR(Service_BOSS, "Could not open BOSS savedata");
-        return ResultCode(1);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
     }
 
     FileSys::Mode open_mode = {};
@@ -151,14 +153,16 @@ void OnlineService::RegisterTask(const u32 size, Kernel::MappedBuffer& buffer) {
 ResultCode OnlineService::UnregisterTask(const u32 size, Kernel::MappedBuffer& buffer) {
     if (size > TASK_ID_SIZE) {
         LOG_WARNING(Service_BOSS, "TaskId cannot be longer than 8");
-        return ResultCode(1);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
     }
 
     std::string task_id(size, 0);
     buffer.Read(task_id.data(), 0, size);
     if (task_id_list.erase(task_id) == 0) {
         LOG_WARNING(Service_BOSS, "TaskId not in list");
-        return ResultCode(1);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
     }
 
     return RESULT_SUCCESS;
@@ -187,20 +191,32 @@ void OnlineService::GetTaskIdList() {
     }
 }
 
-std::vector<FileSys::Entry> OnlineService::GetBossExtDataFiles() {
+FileSys::Path OnlineService::GetBossDataDir() {
+    const u32 high = static_cast<u32>(extdata_id >> 32);
+    const u32 low = static_cast<u32>(extdata_id & 0xFFFFFFFF);
+    return FileSys::ConstructExtDataBinaryPath(1, high, low);
+}
+
+std::unique_ptr<FileSys::ArchiveBackend> OnlineService::OpenBossExtData() {
     FileSys::ArchiveFactory_ExtSaveData boss_extdata_archive_factory(
         FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::ExtSaveDataType::Boss);
     const FileSys::Path boss_path{GetBossDataDir()};
     auto archive_result = boss_extdata_archive_factory.Open(boss_path, 0);
     if (!archive_result.Succeeded()) {
-        LOG_WARNING(Service_BOSS, "Extdata opening failed");
-        return {};
+        LOG_WARNING(Service_BOSS, "Failed to open SpotPass ext data archive with ID '{:#010x}'.",
+                    extdata_id);
+        return nullptr;
     }
+    return std::move(archive_result).Unwrap();
+}
 
-    auto boss_archive = std::move(archive_result).Unwrap();
+std::vector<FileSys::Entry> OnlineService::GetBossExtDataFiles(
+    FileSys::ArchiveBackend* boss_archive) {
     auto dir_result = boss_archive->OpenDirectory("/");
     if (!dir_result.Succeeded()) {
-        LOG_WARNING(Service_BOSS, "Extdata directory opening failed");
+        LOG_WARNING(Service_BOSS,
+                    "Failed to open root directory of SpotPass ext data with ID '{:#010x}'.",
+                    extdata_id);
         return {};
     }
     auto dir = std::move(dir_result).Unwrap();
@@ -219,29 +235,20 @@ std::vector<FileSys::Entry> OnlineService::GetBossExtDataFiles() {
     return boss_files;
 }
 
-FileSys::Path OnlineService::GetBossDataDir() {
-    const u32 high = static_cast<u32>(extdata_id >> 32);
-    const u32 low = static_cast<u32>(extdata_id & 0xFFFFFFFF);
-    return FileSys::ConstructExtDataBinaryPath(1, high, low);
-}
-
 std::vector<NsDataEntry> OnlineService::GetNsDataEntries() {
-    FileSys::ArchiveFactory_ExtSaveData boss_extdata_archive_factory(
-        FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::ExtSaveDataType::Boss);
-    const FileSys::Path boss_path{GetBossDataDir()};
-    auto archive_result = boss_extdata_archive_factory.Open(boss_path, 0);
-    if (!archive_result.Succeeded()) {
-        LOG_WARNING(Service_BOSS, "Extdata opening failed");
+    auto boss_archive = OpenBossExtData();
+    if (!boss_archive) {
         return {};
     }
-    auto boss_archive = std::move(archive_result).Unwrap().get();
 
     std::vector<NsDataEntry> ns_data;
-    std::vector<FileSys::Entry> boss_files = GetBossExtDataFiles();
+    const auto boss_files = GetBossExtDataFiles(boss_archive.get());
     for (const auto& current_file : boss_files) {
         constexpr u32 boss_header_length = 0x34;
         if (current_file.is_directory || current_file.file_size < boss_header_length) {
-            LOG_WARNING(Service_BOSS, "SpotPass extdata contains directory or file is too short");
+            LOG_WARNING(Service_BOSS,
+                        "SpotPass extdata contains directory or file is too short: '{}'",
+                        Common::UTF16ToUTF8(current_file.filename));
             continue;
         }
 
@@ -315,6 +322,129 @@ u16 OnlineService::GetNsDataIdList(const u32 filter, const u32 max_entries,
     return static_cast<u16>(output_entries.size());
 }
 
+std::optional<NsDataEntry> OnlineService::GetNsDataEntryFromId(const u32 ns_data_id) {
+    std::vector<NsDataEntry> ns_data = GetNsDataEntries();
+    const auto entry_iter = std::find_if(ns_data.begin(), ns_data.end(), [ns_data_id](auto entry) {
+        return entry.header.ns_data_id == ns_data_id;
+    });
+    if (entry_iter == ns_data.end()) {
+        LOG_WARNING(Service_BOSS, "Could not find NsData with ID {:#010X}", ns_data_id);
+        return std::nullopt;
+    }
+    return *entry_iter;
+}
+
+ResultCode OnlineService::GetNsDataHeaderInfo(const u32 ns_data_id, const NsDataHeaderInfoType type,
+                                              const u32 size, Kernel::MappedBuffer& buffer) {
+    const auto entry = GetNsDataEntryFromId(ns_data_id);
+    if (!entry.has_value()) {
+        LOG_WARNING(Service_BOSS, "Failed to find NsData entry for ID {:#010X}", ns_data_id);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
+    }
+
+    static constexpr std::array EXPECTED_NS_DATA_HEADER_INFO_SIZES = {
+        sizeof(u64),              // Program ID
+        sizeof(u32),              // Unknown
+        sizeof(u32),              // Data Type
+        sizeof(u32),              // Payload Size
+        sizeof(u32),              // NsData ID
+        sizeof(u32),              // Version
+        sizeof(NsDataHeaderInfo), // Everything
+    };
+    if (size != EXPECTED_NS_DATA_HEADER_INFO_SIZES[static_cast<u8>(type)]) {
+        LOG_WARNING(Service_BOSS, "Invalid size {} for type {}", size, type);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
+    }
+
+    switch (type) {
+    case NsDataHeaderInfoType::ProgramId:
+        buffer.Write(&entry->header.program_id, 0, size);
+        return RESULT_SUCCESS;
+    case NsDataHeaderInfoType::Unknown: {
+        // TODO: Figure out what this is. Stubbed to zero for now.
+        const u32 zero = 0;
+        buffer.Write(&zero, 0, size);
+        return RESULT_SUCCESS;
+    }
+    case NsDataHeaderInfoType::Datatype:
+        buffer.Write(&entry->header.datatype, 0, size);
+        return RESULT_SUCCESS;
+    case NsDataHeaderInfoType::PayloadSize:
+        buffer.Write(&entry->header.payload_size, 0, size);
+        return RESULT_SUCCESS;
+    case NsDataHeaderInfoType::NsDataId:
+        buffer.Write(&entry->header.ns_data_id, 0, size);
+        return RESULT_SUCCESS;
+    case NsDataHeaderInfoType::Version:
+        buffer.Write(&entry->header.version, 0, size);
+        return RESULT_SUCCESS;
+    case NsDataHeaderInfoType::Everything: {
+        const NsDataHeaderInfo info = {
+            .program_id = entry->header.program_id,
+            .datatype = entry->header.datatype,
+            .payload_size = entry->header.payload_size,
+            .ns_data_id = entry->header.ns_data_id,
+            .version = entry->header.version,
+        };
+        buffer.Write(&info, 0, size);
+        return RESULT_SUCCESS;
+    }
+    default:
+        LOG_WARNING(Service_BOSS, "Unknown header info type {}", type);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
+    }
+}
+
+ResultVal<size_t> OnlineService::ReadNsData(const u32 ns_data_id, const u64 offset, const u32 size,
+                                            Kernel::MappedBuffer& buffer) {
+    std::optional<NsDataEntry> entry = GetNsDataEntryFromId(ns_data_id);
+    if (!entry.has_value()) {
+        LOG_WARNING(Service_BOSS, "Failed to find NsData entry for ID {:#010X}", ns_data_id);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
+    }
+
+    if (entry->header.payload_size < size + offset) {
+        LOG_WARNING(Service_BOSS,
+                    "Invalid request to read {:#010X} bytes at offset {:#010X}, payload "
+                    "length is {:#010X}",
+                    size, offset, static_cast<u32>(entry->header.payload_size));
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
+    }
+
+    auto boss_archive = OpenBossExtData();
+    if (!boss_archive) {
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
+    }
+
+    FileSys::Path file_path = fmt::format("/{}", entry->filename);
+    FileSys::Mode mode{};
+    mode.read_flag.Assign(1);
+    auto file_result = boss_archive->OpenFile(file_path, mode);
+    if (!file_result.Succeeded()) {
+        LOG_WARNING(Service_BOSS, "Failed to open SpotPass extdata file '{}'.", entry->filename);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
+    }
+
+    auto file = std::move(file_result).Unwrap();
+    std::vector<u8> ns_data_array(size);
+    auto read_result = file->Read(sizeof(BossHeader) + offset, size, ns_data_array.data());
+    if (!read_result.Succeeded()) {
+        LOG_WARNING(Service_BOSS, "Failed to read SpotPass extdata file '{}'.", entry->filename);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
+    }
+
+    buffer.Write(ns_data_array.data(), 0, size);
+    return read_result;
+}
+
 template <class... Ts>
 struct overload : Ts... {
     using Ts::operator()...;
@@ -325,8 +455,9 @@ overload(Ts...) -> overload<Ts...>;
 ResultCode OnlineService::SendProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer) {
     const auto property_id = static_cast<PropertyID>(id);
     if (!current_props.properties.contains(property_id)) {
-        LOG_ERROR(Service_BOSS, "Unknown property with id {:#06x}", property_id);
-        return ResultCode(1);
+        LOG_ERROR(Service_BOSS, "Unknown property with ID {:#06x} and size {}", property_id, size);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
     }
 
     auto& prop = current_props.properties[property_id];
@@ -365,8 +496,9 @@ ResultCode OnlineService::ReceiveProperty(const u16 id, const u32 size,
                                           Kernel::MappedBuffer& buffer) {
     const auto property_id = static_cast<PropertyID>(id);
     if (!current_props.properties.contains(property_id)) {
-        LOG_ERROR(Service_BOSS, "Unknown property with id {:#06x}", property_id);
-        return ResultCode(1);
+        LOG_ERROR(Service_BOSS, "Unknown property with ID {:#06x} and size {}", property_id, size);
+        // TODO: Proper error code.
+        return RESULT_UNKNOWN;
     }
 
     auto write_pod = [&]<typename T>(T& cur_prop) {
diff --git a/src/core/hle/service/boss/online_service.h b/src/core/hle/service/boss/online_service.h
index b059060cf..ec2b18a79 100644
--- a/src/core/hle/service/boss/online_service.h
+++ b/src/core/hle/service/boss/online_service.h
@@ -17,6 +17,7 @@ class MappedBuffer;
 }
 
 namespace FileSys {
+class ArchiveBackend;
 struct Entry;
 class Path;
 } // namespace FileSys
@@ -67,6 +68,27 @@ struct NsDataEntry {
     BossHeader header;
 };
 
+enum class NsDataHeaderInfoType : u8 {
+    ProgramId = 0,
+    Unknown = 1,
+    Datatype = 2,
+    PayloadSize = 3,
+    NsDataId = 4,
+    Version = 5,
+    Everything = 6,
+};
+
+struct NsDataHeaderInfo {
+    u64 program_id;
+    INSERT_PADDING_BYTES(4);
+    u32 datatype;
+    u32 payload_size;
+    u32 ns_data_id;
+    u32 version;
+    INSERT_PADDING_BYTES(4);
+};
+static_assert(sizeof(NsDataHeaderInfo) == 0x20, "NsDataHeaderInfo has incorrect size");
+
 enum class PropertyID : u16 {
     Interval = 0x03,
     Duration = 0x04,
@@ -144,11 +166,17 @@ public:
     ResultCode UnregisterTask(const u32 size, Kernel::MappedBuffer& buffer);
     void GetTaskIdList();
     u16 GetNsDataIdList(const u32 filter, const u32 max_entries, Kernel::MappedBuffer& buffer);
+    std::optional<NsDataEntry> GetNsDataEntryFromId(const u32 ns_data_id);
+    ResultCode GetNsDataHeaderInfo(const u32 ns_data_id, const NsDataHeaderInfoType type,
+                                   const u32 size, Kernel::MappedBuffer& buffer);
+    ResultVal<size_t> ReadNsData(const u32 ns_data_id, const u64 offset, const u32 size,
+                                 Kernel::MappedBuffer& buffer);
     ResultCode SendProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer);
     ResultCode ReceiveProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer);
 
 private:
-    std::vector<FileSys::Entry> GetBossExtDataFiles();
+    std::unique_ptr<FileSys::ArchiveBackend> OpenBossExtData();
+    std::vector<FileSys::Entry> GetBossExtDataFiles(FileSys::ArchiveBackend* boss_archive);
     FileSys::Path GetBossDataDir();
     std::vector<NsDataEntry> GetNsDataEntries();