diff --git a/Package.swift b/Package.swift
index 1c347fa7f59cb8ac18b1cabd166caaa5f9e9d4a3..5f0bf3edb9c89e60b400bac60b999d01736bd514 100644
--- a/Package.swift
+++ b/Package.swift
@@ -26,6 +26,12 @@ let package = Package(
       targets: ["ElixxirDAppsSDK"]
     ),
   ],
+  dependencies: [
+    .package(
+      url: "https://github.com/pointfreeco/swift-custom-dump.git",
+      .upToNextMajor(from: "0.4.0")
+    ),
+  ],
   targets: [
     .target(
       name: "ElixxirDAppsSDK",
@@ -34,6 +40,17 @@ let package = Package(
       ],
       swiftSettings: swiftSettings
     ),
+    .testTarget(
+      name: "ElixxirDAppsSDKTests",
+      dependencies: [
+        .target(name: "ElixxirDAppsSDK"),
+        .product(
+          name: "CustomDump",
+          package: "swift-custom-dump"
+        ),
+      ],
+      swiftSettings: swiftSettings
+    ),
     .binaryTarget(
       name: "Bindings",
       path: "Frameworks/Bindings.xcframework"
diff --git a/Sources/ElixxirDAppsSDK/Fact.swift b/Sources/ElixxirDAppsSDK/Fact.swift
new file mode 100644
index 0000000000000000000000000000000000000000..fa4a277b64bdbfedd773167da10d29dc4bf0d379
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/Fact.swift
@@ -0,0 +1,19 @@
+public struct Fact: Equatable {
+  public init(
+    fact: String,
+    type: Int
+  ) {
+    self.fact = fact
+    self.type = type
+  }
+
+  public var fact: String
+  public var type: Int
+}
+
+extension Fact: Codable {
+  enum CodingKeys: String, CodingKey {
+    case fact = "Fact"
+    case type = "Type"
+  }
+}
diff --git a/Sources/ElixxirDAppsSDK/Identity.swift b/Sources/ElixxirDAppsSDK/Identity.swift
new file mode 100644
index 0000000000000000000000000000000000000000..f192f6af836c7e7ffc85122e4fc5e49f7a042430
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/Identity.swift
@@ -0,0 +1,29 @@
+import Foundation
+
+public struct Identity: Equatable {
+  public init(
+    id: Data,
+    rsaPrivatePem: Data,
+    salt: Data,
+    dhKeyPrivate: Data
+  ) {
+    self.id = id
+    self.rsaPrivatePem = rsaPrivatePem
+    self.salt = salt
+    self.dhKeyPrivate = dhKeyPrivate
+  }
+
+  public var id: Data
+  public var rsaPrivatePem: Data
+  public var salt: Data
+  public var dhKeyPrivate: Data
+}
+
+extension Identity: Codable {
+  enum CodingKeys: String, CodingKey {
+    case id = "ID"
+    case rsaPrivatePem = "RSAPrivatePem"
+    case salt = "Salt"
+    case dhKeyPrivate = "DHKeyPrivate"
+  }
+}
diff --git a/Sources/ElixxirDAppsSDK/Message.swift b/Sources/ElixxirDAppsSDK/Message.swift
new file mode 100644
index 0000000000000000000000000000000000000000..b6fc6c4c205d3e7299804dbaac3b9f3f0fdb782a
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/Message.swift
@@ -0,0 +1,49 @@
+import Foundation
+
+public struct Message: Equatable {
+  public init(
+    messageType: Int,
+    id: Data,
+    payload: Data,
+    sender: Data,
+    recipientId: Data,
+    ephemeralId: Int,
+    timestamp: Int,
+    encrypted: Bool,
+    roundId: Int
+  ) {
+    self.messageType = messageType
+    self.id = id
+    self.payload = payload
+    self.sender = sender
+    self.recipientId = recipientId
+    self.ephemeralId = ephemeralId
+    self.timestamp = timestamp
+    self.encrypted = encrypted
+    self.roundId = roundId
+  }
+
+  public var messageType: Int
+  public var id: Data
+  public var payload: Data
+  public var sender: Data
+  public var recipientId: Data
+  public var ephemeralId: Int
+  public var timestamp: Int
+  public var encrypted: Bool
+  public var roundId: Int
+}
+
+extension Message: Codable {
+  enum CodingKeys: String, CodingKey {
+    case messageType = "MessageType"
+    case id = "ID"
+    case payload = "Payload"
+    case sender = "Sender"
+    case recipientId = "RecipientID"
+    case ephemeralId = "EphemeralID"
+    case timestamp = "Timestamp"
+    case encrypted = "Encrypted"
+    case roundId = "RoundId"
+  }
+}
diff --git a/Sources/ElixxirDAppsSDK/MessageSendReport.swift b/Sources/ElixxirDAppsSDK/MessageSendReport.swift
new file mode 100644
index 0000000000000000000000000000000000000000..687fc08d83d38b215b27a4a804134c19f99d8505
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/MessageSendReport.swift
@@ -0,0 +1,51 @@
+import Foundation
+
+public struct MessageSendReport: Equatable {
+  public init(
+    roundList: [Int],
+    messageId: Data,
+    timestamp: Int
+  ) {
+    self.roundList = roundList
+    self.messageId = messageId
+    self.timestamp = timestamp
+  }
+
+  public var roundList: [Int]
+  public var messageId: Data
+  public var timestamp: Int
+}
+
+extension MessageSendReport: Codable {
+  enum CodingKeys: String, CodingKey {
+    case roundList = "RoundList"
+    case messageId = "MessageID"
+    case timestamp = "Timestamp"
+  }
+
+  enum RoundListCodingKeys: String, CodingKey {
+    case rounds = "Rounds"
+  }
+
+  public init(from decoder: Decoder) throws {
+    let container = try decoder.container(keyedBy: CodingKeys.self)
+    messageId = try container.decode(Data.self, forKey: .messageId)
+    timestamp = try container.decode(Int.self, forKey: .timestamp)
+    let roundListContainer = try container.nestedContainer(
+      keyedBy: RoundListCodingKeys.self,
+      forKey: .roundList
+    )
+    roundList = try roundListContainer.decode([Int].self, forKey: .rounds)
+  }
+
+  public func encode(to encoder: Encoder) throws {
+    var container = encoder.container(keyedBy: CodingKeys.self)
+    try container.encode(messageId, forKey: .messageId)
+    try container.encode(timestamp, forKey: .timestamp)
+    var roundListContainer = container.nestedContainer(
+      keyedBy: RoundListCodingKeys.self,
+      forKey: .roundList
+    )
+    try roundListContainer.encode(roundList, forKey: .rounds)
+  }
+}
diff --git a/Sources/ElixxirDAppsSDK/RestlikeMessage.swift b/Sources/ElixxirDAppsSDK/RestlikeMessage.swift
new file mode 100644
index 0000000000000000000000000000000000000000..48b0e5ef788976a0af37be7b843013e708987656
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/RestlikeMessage.swift
@@ -0,0 +1,37 @@
+import Foundation
+
+public struct RestlikeMessage: Equatable {
+  public init(
+    version: Int,
+    headers: Data,
+    content: Data,
+    method: Int,
+    uri: String,
+    error: String
+  ) {
+    self.version = version
+    self.headers = headers
+    self.content = content
+    self.method = method
+    self.uri = uri
+    self.error = error
+  }
+
+  public var version: Int
+  public var headers: Data
+  public var content: Data
+  public var method: Int
+  public var uri: String
+  public var error: String
+}
+
+extension RestlikeMessage: Codable {
+  enum CodingKeys: String, CodingKey {
+    case version = "Version"
+    case headers = "Headers"
+    case content = "Content"
+    case method = "Method"
+    case uri = "URI"
+    case error = "Error"
+  }
+}
diff --git a/Tests/ElixxirDAppsSDKTests/FactTests.swift b/Tests/ElixxirDAppsSDKTests/FactTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..21820a78c9a744322a8d81823f81d486ace91be6
--- /dev/null
+++ b/Tests/ElixxirDAppsSDKTests/FactTests.swift
@@ -0,0 +1,30 @@
+import CustomDump
+import XCTest
+@testable import ElixxirDAppsSDK
+
+final class FactTests: XCTestCase {
+  func testCoding() throws {
+    let jsonString = """
+    {
+      "Fact": "Zezima",
+      "Type": 0
+    }
+    """
+    let jsonData = jsonString.data(using: .utf8)!
+    let decoder = JSONDecoder()
+    decoder.dataDecodingStrategy = .base64
+    let fact = try decoder.decode(Fact.self, from: jsonData)
+
+    XCTAssertNoDifference(fact, Fact(
+      fact: "Zezima",
+      type: 0
+    ))
+
+    let encoder = JSONEncoder()
+    encoder.dataEncodingStrategy = .base64
+    let encodedFact = try encoder.encode(fact)
+    let decodedFact = try decoder.decode(Fact.self, from: encodedFact)
+
+    XCTAssertNoDifference(decodedFact, fact)
+  }
+}
diff --git a/Tests/ElixxirDAppsSDKTests/IdentityTests.swift b/Tests/ElixxirDAppsSDKTests/IdentityTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..b517634542976037ab5793b47d0314b0cc5f15eb
--- /dev/null
+++ b/Tests/ElixxirDAppsSDKTests/IdentityTests.swift
@@ -0,0 +1,34 @@
+import CustomDump
+import XCTest
+@testable import ElixxirDAppsSDK
+
+final class IdentityTests: XCTestCase {
+  func testCoding() throws {
+    let jsonString = """
+    {
+      "ID": "emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+      "RSAPrivatePem": "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBNU15dTdhYjBJOS9UL1BFUUxtd2x3ejZHV3FjMUNYemVIVXhoVEc4bmg1WWRWSXMxCmJ2THpBVjNOMDJxdXN6K2s4TVFEWjBtejMzdkswUmhPczZIY0NUSFdzTEpXRkE5WWpzWWlCRi9qTDd1bmd1ckIKL2tvK1JJSnNrWGFWaEZaazRGdERoRXhTNWY4RnR0Qmk1NmNLZmdJQlVKT3ozZi9qQllTMkxzMlJ6cWV5YXM3SApjV2RaME9TclBTT3BiYlViU1FPbS9LWnlweGZHU21yZ2oxRUZuU1dZZ2xGZTdUOTRPbHF5MG14QTV5clVXbHorCk9sK3hHbXpCNUp4WUFSMU9oMFQrQTk4RWMrTUZHNm43L1MraDdzRDgybGRnVnJmbStFTzRCdmFKeTRESGZGMWgKNnp6QnVnY25NUVFGc0dLeDFYWC9COTVMdUpPVjdyeXlDbzZGbHdJREFRQUJBb0lCQVFDaUh6OGNlcDZvQk9RTAphUzBVRitHeU5VMnlVcVRNTWtTWThoUkh1c09CMmFheXoybHZVb3RLUHBPbjZRSWRWVTJrcE4vY2dtY0lSb2x5CkhBMDRUOHJBWVNaRlVqaVlRajkzKzRFREpJYXd2Z0YyVEs1bFoyb3oxVTdreStncU82V0RMR2Z0Q0wvODVQWEIKa210aXhnUXpRV3g1RWcvemtHdm03eURBalQxeDloNytsRjJwNFlBam5kT2xTS0dmQjFZeTR1RXBQd0kwc1lWdgpKQWc0MEFxbllZUmt4emJPbmQxWGNjdEJFN2Z1VDdrWXhoeSs3WXYrUTJwVy9BYmh6NGlHOEY1MW9GMGZwV0czCmlISDhsVXZFTkp2SUZEVHZ0UEpESlFZalBRN3lUbGlGZUdrMXZUQkcyQkpQNExzVzhpbDZOeUFuRktaY1hOQ24KeHVCendiSlJBb0dCQVBUK0dGTVJGRHRHZVl6NmwzZmg3UjJ0MlhrMysvUmpvR3BDUWREWDhYNERqR1pVd1RGVQpOS2tQTTNjS29ia2RBYlBDb3FpL0tOOVBibk9QVlZ3R3JkSE9vSnNibFVHYmJGamFTUzJQMFZnNUVhTC9rT2dUCmxMMUdoVFpIUWk1VUlMM0p4M1Z3T0ZRQ3RQOU1UQlQ0UEQvcEFLbDg3VTJXN3JTY1dGV1ZGbFNkQW9HQkFPOFUKVmhHWkRpVGFKTWVtSGZIdVYrNmtzaUlsam9aUVVzeGpmTGNMZ2NjV2RmTHBqS0ZWTzJNN3NqcEJEZ0w4NmFnegorVk14ZkQzZ1l0SmNWN01aMVcwNlZ6TlNVTHh3a1dRY1hXUWdDaXc5elpyYlhCUmZRNUVjMFBlblVoWWVwVzF5CkpkTC8rSlpQeDJxSzVrQytiWU5EdmxlNWdpcjlDSGVzTlR5enVyckRBb0dCQUl0cTJnN1RaazhCSVFUUVNrZ24Kb3BkRUtzRW4wZExXcXlBdENtVTlyaWpHL2l2eHlXczMveXZDQWNpWm5VVEp0QUZISHVlbXVTeXplQ2g5QmRkegoyWkRPNUdqQVBxVHlQS3NudFlNZkY4UDczZ1NES1VSWWVFbHFDejdET0c5QzRzcitPK3FoN1B3cCtqUmFoK1ZiCkNuWllNMDlBVDQ3YStJYUJmbWRkaXpLbEFvR0JBSmo1dkRDNmJIQnNISWlhNUNJL1RZaG5YWXUzMkVCYytQM0sKMHF3VThzOCtzZTNpUHBla2Y4RjVHd3RuUU4zc2tsMk1GQWFGYldmeVFZazBpUEVTb0p1cGJzNXA1enNNRkJ1bwpncUZrVnQ0RUZhRDJweTVwM2tQbDJsZjhlZXVwWkZScGE0WmRQdVIrMjZ4eWYrNEJhdlZJeld3NFNPL1V4Q3crCnhqbTNEczRkQW9HQWREL0VOa1BjU004c1BCM3JSWW9MQ2twcUV2U0MzbVZSbjNJd3c1WFAwcDRRVndhRmR1ckMKYUhtSE1EekNrNEUvb0haQVhFdGZ2S2tRaUI4MXVYM2c1aVo4amdYUVhXUHRteTVIcVVhcWJYUTlENkxWc3B0egpKL3R4SWJLMXp5c1o2bk9IY1VoUUwyVVF6SlBBRThZNDdjYzVzTThEN3kwZjJ0QURTQUZNMmN3PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ==",
+      "Salt": "4kk02v0NIcGtlobZ/xkxqWz8uH/ams/gjvQm14QT0dI=",
+      "DHKeyPrivate": "eyJWYWx1ZSI6NDU2MDgzOTEzMjA0OTIyODA5Njg2MDI3MzQ0MzM3OTA0MzAyODYwMjM2NDk2NDM5NDI4NTcxMTMwNDMzOTQwMzgyMTIyMjY4OTQzNTMyMjIyMzc1MTkzNTEzMjU4MjA4MDA0NTczMDY4MjEwNzg2NDI5NjA1MjA0OTA3MjI2ODI5OTc3NTczMDkxODY0NTY3NDExMDExNjQxNCwiRmluZ2VycHJpbnQiOjE2ODAxNTQxNTExMjMzMDk4MzYzfQ=="
+    }
+    """
+    let jsonData = jsonString.data(using: .utf8)!
+    let decoder = JSONDecoder()
+    decoder.dataDecodingStrategy = .base64
+    let identity = try decoder.decode(Identity.self, from: jsonData)
+
+    XCTAssertNoDifference(identity, Identity(
+      id: Data(base64Encoded: "emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD")!,
+      rsaPrivatePem: Data(base64Encoded: "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBNU15dTdhYjBJOS9UL1BFUUxtd2x3ejZHV3FjMUNYemVIVXhoVEc4bmg1WWRWSXMxCmJ2THpBVjNOMDJxdXN6K2s4TVFEWjBtejMzdkswUmhPczZIY0NUSFdzTEpXRkE5WWpzWWlCRi9qTDd1bmd1ckIKL2tvK1JJSnNrWGFWaEZaazRGdERoRXhTNWY4RnR0Qmk1NmNLZmdJQlVKT3ozZi9qQllTMkxzMlJ6cWV5YXM3SApjV2RaME9TclBTT3BiYlViU1FPbS9LWnlweGZHU21yZ2oxRUZuU1dZZ2xGZTdUOTRPbHF5MG14QTV5clVXbHorCk9sK3hHbXpCNUp4WUFSMU9oMFQrQTk4RWMrTUZHNm43L1MraDdzRDgybGRnVnJmbStFTzRCdmFKeTRESGZGMWgKNnp6QnVnY25NUVFGc0dLeDFYWC9COTVMdUpPVjdyeXlDbzZGbHdJREFRQUJBb0lCQVFDaUh6OGNlcDZvQk9RTAphUzBVRitHeU5VMnlVcVRNTWtTWThoUkh1c09CMmFheXoybHZVb3RLUHBPbjZRSWRWVTJrcE4vY2dtY0lSb2x5CkhBMDRUOHJBWVNaRlVqaVlRajkzKzRFREpJYXd2Z0YyVEs1bFoyb3oxVTdreStncU82V0RMR2Z0Q0wvODVQWEIKa210aXhnUXpRV3g1RWcvemtHdm03eURBalQxeDloNytsRjJwNFlBam5kT2xTS0dmQjFZeTR1RXBQd0kwc1lWdgpKQWc0MEFxbllZUmt4emJPbmQxWGNjdEJFN2Z1VDdrWXhoeSs3WXYrUTJwVy9BYmh6NGlHOEY1MW9GMGZwV0czCmlISDhsVXZFTkp2SUZEVHZ0UEpESlFZalBRN3lUbGlGZUdrMXZUQkcyQkpQNExzVzhpbDZOeUFuRktaY1hOQ24KeHVCendiSlJBb0dCQVBUK0dGTVJGRHRHZVl6NmwzZmg3UjJ0MlhrMysvUmpvR3BDUWREWDhYNERqR1pVd1RGVQpOS2tQTTNjS29ia2RBYlBDb3FpL0tOOVBibk9QVlZ3R3JkSE9vSnNibFVHYmJGamFTUzJQMFZnNUVhTC9rT2dUCmxMMUdoVFpIUWk1VUlMM0p4M1Z3T0ZRQ3RQOU1UQlQ0UEQvcEFLbDg3VTJXN3JTY1dGV1ZGbFNkQW9HQkFPOFUKVmhHWkRpVGFKTWVtSGZIdVYrNmtzaUlsam9aUVVzeGpmTGNMZ2NjV2RmTHBqS0ZWTzJNN3NqcEJEZ0w4NmFnegorVk14ZkQzZ1l0SmNWN01aMVcwNlZ6TlNVTHh3a1dRY1hXUWdDaXc5elpyYlhCUmZRNUVjMFBlblVoWWVwVzF5CkpkTC8rSlpQeDJxSzVrQytiWU5EdmxlNWdpcjlDSGVzTlR5enVyckRBb0dCQUl0cTJnN1RaazhCSVFUUVNrZ24Kb3BkRUtzRW4wZExXcXlBdENtVTlyaWpHL2l2eHlXczMveXZDQWNpWm5VVEp0QUZISHVlbXVTeXplQ2g5QmRkegoyWkRPNUdqQVBxVHlQS3NudFlNZkY4UDczZ1NES1VSWWVFbHFDejdET0c5QzRzcitPK3FoN1B3cCtqUmFoK1ZiCkNuWllNMDlBVDQ3YStJYUJmbWRkaXpLbEFvR0JBSmo1dkRDNmJIQnNISWlhNUNJL1RZaG5YWXUzMkVCYytQM0sKMHF3VThzOCtzZTNpUHBla2Y4RjVHd3RuUU4zc2tsMk1GQWFGYldmeVFZazBpUEVTb0p1cGJzNXA1enNNRkJ1bwpncUZrVnQ0RUZhRDJweTVwM2tQbDJsZjhlZXVwWkZScGE0WmRQdVIrMjZ4eWYrNEJhdlZJeld3NFNPL1V4Q3crCnhqbTNEczRkQW9HQWREL0VOa1BjU004c1BCM3JSWW9MQ2twcUV2U0MzbVZSbjNJd3c1WFAwcDRRVndhRmR1ckMKYUhtSE1EekNrNEUvb0haQVhFdGZ2S2tRaUI4MXVYM2c1aVo4amdYUVhXUHRteTVIcVVhcWJYUTlENkxWc3B0egpKL3R4SWJLMXp5c1o2bk9IY1VoUUwyVVF6SlBBRThZNDdjYzVzTThEN3kwZjJ0QURTQUZNMmN3PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ==")!,
+      salt: Data(base64Encoded: "4kk02v0NIcGtlobZ/xkxqWz8uH/ams/gjvQm14QT0dI=")!,
+      dhKeyPrivate: Data(base64Encoded: "eyJWYWx1ZSI6NDU2MDgzOTEzMjA0OTIyODA5Njg2MDI3MzQ0MzM3OTA0MzAyODYwMjM2NDk2NDM5NDI4NTcxMTMwNDMzOTQwMzgyMTIyMjY4OTQzNTMyMjIyMzc1MTkzNTEzMjU4MjA4MDA0NTczMDY4MjEwNzg2NDI5NjA1MjA0OTA3MjI2ODI5OTc3NTczMDkxODY0NTY3NDExMDExNjQxNCwiRmluZ2VycHJpbnQiOjE2ODAxNTQxNTExMjMzMDk4MzYzfQ==")!
+    ))
+
+    let encoder = JSONEncoder()
+    encoder.dataEncodingStrategy = .base64
+    let encodedIdentity = try encoder.encode(identity)
+    let decodedIdentity = try decoder.decode(Identity.self, from: encodedIdentity)
+
+    XCTAssertNoDifference(decodedIdentity, identity)
+  }
+}
diff --git a/Tests/ElixxirDAppsSDKTests/MessageSendReportTests.swift b/Tests/ElixxirDAppsSDKTests/MessageSendReportTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..d78a7eea7b4bef565128dc9c350bd4361469daef
--- /dev/null
+++ b/Tests/ElixxirDAppsSDKTests/MessageSendReportTests.swift
@@ -0,0 +1,34 @@
+import CustomDump
+import XCTest
+@testable import ElixxirDAppsSDK
+
+final class MessageSendReportTests: XCTestCase {
+  func testCoding() throws {
+    let jsonString = """
+    {
+      "RoundList": {
+        "Rounds": [1,5,9]
+      },
+      "MessageID": "51Yy47uZbP0o2Y9B/kkreDLTB6opUol3M3mYiY2dcdQ=",
+      "Timestamp": 1653582683183384000
+    }
+    """
+    let jsonData = jsonString.data(using: .utf8)!
+    let decoder = JSONDecoder()
+    decoder.dataDecodingStrategy = .base64
+    let report = try decoder.decode(MessageSendReport.self, from: jsonData)
+
+    XCTAssertNoDifference(report, MessageSendReport(
+      roundList: [1, 5, 9],
+      messageId: Data(base64Encoded: "51Yy47uZbP0o2Y9B/kkreDLTB6opUol3M3mYiY2dcdQ=")!,
+      timestamp: 1_653_582_683_183_384_000
+    ))
+
+    let encoder = JSONEncoder()
+    encoder.dataEncodingStrategy = .base64
+    let encodedReport = try encoder.encode(report)
+    let decodedReport = try decoder.decode(MessageSendReport.self, from: encodedReport)
+
+    XCTAssertNoDifference(decodedReport, report)
+  }
+}
diff --git a/Tests/ElixxirDAppsSDKTests/MessageTests.swift b/Tests/ElixxirDAppsSDKTests/MessageTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..148314598a7a04b8600ea4322f83842e69d24d21
--- /dev/null
+++ b/Tests/ElixxirDAppsSDKTests/MessageTests.swift
@@ -0,0 +1,44 @@
+import CustomDump
+import XCTest
+@testable import ElixxirDAppsSDK
+
+final class MessageTests: XCTestCase {
+  func testCoding() throws {
+    let jsonString = """
+    {
+      "MessageType": 1,
+      "ID": "EB/70R5HYEw5htZ4Hg9ondrn3+cAc/lH2G0mjQMja3w=",
+      "Payload": "7TzZKgNphT5UooNM7mDSwtVcIs8AIu4vMKm4ld6GSR8YX5GrHirixUBAejmsgdroRJyo06TkIVef7UM9FN8YfQ==",
+      "Sender": "emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+      "RecipientID": "amFrZXh4MzYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+      "EphemeralID": 17,
+      "Timestamp": 1653580439357351000,
+      "Encrypted": false,
+      "RoundId": 19
+    }
+    """
+    let jsonData = jsonString.data(using: .utf8)!
+    let decoder = JSONDecoder()
+    decoder.dataDecodingStrategy = .base64
+    let message = try decoder.decode(Message.self, from: jsonData)
+
+    XCTAssertNoDifference(message, Message(
+      messageType: 1,
+      id: Data(base64Encoded: "EB/70R5HYEw5htZ4Hg9ondrn3+cAc/lH2G0mjQMja3w=")!,
+      payload: Data(base64Encoded: "7TzZKgNphT5UooNM7mDSwtVcIs8AIu4vMKm4ld6GSR8YX5GrHirixUBAejmsgdroRJyo06TkIVef7UM9FN8YfQ==")!,
+      sender: Data(base64Encoded: "emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD")!,
+      recipientId: Data(base64Encoded: "amFrZXh4MzYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD")!,
+      ephemeralId: 17,
+      timestamp: 1_653_580_439_357_351_000,
+      encrypted: false,
+      roundId: 19
+    ))
+
+    let encoder = JSONEncoder()
+    encoder.dataEncodingStrategy = .base64
+    let encodedMessage = try encoder.encode(message)
+    let decodedMessage = try decoder.decode(Message.self, from: encodedMessage)
+
+    XCTAssertNoDifference(decodedMessage, message)
+  }
+}
diff --git a/Tests/ElixxirDAppsSDKTests/RestlikeMessageTests.swift b/Tests/ElixxirDAppsSDKTests/RestlikeMessageTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..164fce5bcc4822d6c8c33b8133f11486cdc953b7
--- /dev/null
+++ b/Tests/ElixxirDAppsSDKTests/RestlikeMessageTests.swift
@@ -0,0 +1,38 @@
+import CustomDump
+import XCTest
+@testable import ElixxirDAppsSDK
+
+final class RestlikeMessageTests: XCTestCase {
+  func testCoding() throws {
+    let jsonString = """
+    {
+      "Version": 1,
+      "Headers": "Y29udGVudHM6YXBwbGljYXRpb24vanNvbg==",
+      "Content": "VGhpcyBpcyBhIHJlc3RsaWtlIG1lc3NhZ2U=",
+      "Method": 2,
+      "URI": "xx://CmixRestlike/rest",
+      "Error": ""
+    }
+    """
+    let jsonData = jsonString.data(using: .utf8)!
+    let decoder = JSONDecoder()
+    decoder.dataDecodingStrategy = .base64
+    let message = try decoder.decode(RestlikeMessage.self, from: jsonData)
+
+    XCTAssertNoDifference(message, RestlikeMessage(
+      version: 1,
+      headers: Data(base64Encoded: "Y29udGVudHM6YXBwbGljYXRpb24vanNvbg==")!,
+      content: Data(base64Encoded: "VGhpcyBpcyBhIHJlc3RsaWtlIG1lc3NhZ2U=")!,
+      method: 2,
+      uri: "xx://CmixRestlike/rest",
+      error: ""
+    ))
+
+    let encoder = JSONEncoder()
+    encoder.dataEncodingStrategy = .base64
+    let encodedMessage = try encoder.encode(message)
+    let decodedMessage = try decoder.decode(RestlikeMessage.self, from: encodedMessage)
+
+    XCTAssertNoDifference(decodedMessage, message)
+  }
+}