diff --git a/Sources/XXClient/Models/MessageService.swift b/Sources/XXClient/Models/MessageService.swift
new file mode 100644
index 0000000000000000000000000000000000000000..583225e0cbcedd9a9aad3a75782521e65858a95b
--- /dev/null
+++ b/Sources/XXClient/Models/MessageService.swift
@@ -0,0 +1,43 @@
+import Foundation
+
+public struct MessageService: Equatable {
+  public init(
+    identifier: Data,
+    tag: String,
+    metadata: Data
+  ) {
+    self.identifier = identifier
+    self.tag = tag
+    self.metadata = metadata
+  }
+
+  public var identifier: Data
+  public var tag: String
+  public var metadata: Data
+}
+
+extension MessageService: Codable {
+  enum CodingKeys: String, CodingKey {
+    case identifier = "Identifier"
+    case tag = "Tag"
+    case metadata = "Metadata"
+  }
+
+  public static func decode(_ data: Data) throws -> Self {
+    try JSONDecoder().decode(Self.self, from: data)
+  }
+
+  public func encode() throws -> Data {
+    try JSONEncoder().encode(self)
+  }
+}
+
+extension Array where Element == MessageService {
+  public static func decode(_ data: Data) throws -> Self {
+    try JSONDecoder().decode(Self.self, from: data)
+  }
+
+  public func encode() throws -> Data {
+    try JSONEncoder().encode(self)
+  }
+}
diff --git a/Tests/XXClientTests/Models/MessageServiceTests.swift b/Tests/XXClientTests/Models/MessageServiceTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..e0a0d9bad5bca5fbd1418886a4c5709c9b196f21
--- /dev/null
+++ b/Tests/XXClientTests/Models/MessageServiceTests.swift
@@ -0,0 +1,56 @@
+import CustomDump
+import XCTest
+@testable import XXClient
+
+final class MessageServiceTests: XCTestCase {
+  func testCoding() throws {
+    let identifierB64 = "AQID"
+    let tag = "TestTag 2"
+    let metadataB64 = "BAUG"
+    let jsonString = """
+    {
+     "Identifier": "\(identifierB64)",
+     "Tag": "\(tag)",
+     "Metadata": "\(metadataB64)"
+    }
+    """
+    let jsonData = jsonString.data(using: .utf8)!
+    let model = try MessageService.decode(jsonData)
+
+    XCTAssertNoDifference(model, MessageService(
+      identifier: Data(base64Encoded: identifierB64)!,
+      tag: tag,
+      metadata: Data(base64Encoded: metadataB64)!
+    ))
+
+    let encodedModel = try model.encode()
+    let decodedModel = try MessageService.decode(encodedModel)
+
+    XCTAssertNoDifference(decodedModel, model)
+  }
+
+  func testCodingArray() throws {
+    let models = [
+      MessageService(
+        identifier: "service1-id".data(using: .utf8)!,
+        tag: "service1-tag",
+        metadata: "service1-metadata".data(using: .utf8)!
+      ),
+      MessageService(
+        identifier: "service2-id".data(using: .utf8)!,
+        tag: "service2-tag",
+        metadata: "service2-metadata".data(using: .utf8)!
+      ),
+      MessageService(
+        identifier: "service3-id".data(using: .utf8)!,
+        tag: "service3-tag",
+        metadata: "service3-metadata".data(using: .utf8)!
+      ),
+    ]
+
+    let encodedModels = try models.encode()
+    let decodedModels = try [MessageService].decode(encodedModels)
+
+    XCTAssertNoDifference(models, decodedModels)
+  }
+}