diff --git a/Frameworks/Bindings.xcframework/ios-arm64/Bindings.framework/Versions/A/Bindings b/Frameworks/Bindings.xcframework/ios-arm64/Bindings.framework/Versions/A/Bindings
index fd0c94b2e69e400cdce3077fb499b0139ac3e3a8..770e77eb5a33a73b4d48b44b702888e28f51682a 100644
Binary files a/Frameworks/Bindings.xcframework/ios-arm64/Bindings.framework/Versions/A/Bindings and b/Frameworks/Bindings.xcframework/ios-arm64/Bindings.framework/Versions/A/Bindings differ
diff --git a/Frameworks/Bindings.xcframework/ios-arm64/Bindings.framework/Versions/A/Headers/Bindings.objc.h b/Frameworks/Bindings.xcframework/ios-arm64/Bindings.framework/Versions/A/Headers/Bindings.objc.h
index 15e54413e58bd26f6498c353c161b67e8d7c92e5..40a89ee2ee4afde62d99dcdcac9ef77d09c7c663 100644
--- a/Frameworks/Bindings.xcframework/ios-arm64/Bindings.framework/Versions/A/Headers/Bindings.objc.h
+++ b/Frameworks/Bindings.xcframework/ios-arm64/Bindings.framework/Versions/A/Headers/Bindings.objc.h
@@ -1182,7 +1182,26 @@ the first contact is the leader/creator of the group.
 All subsequent members are ordered by their ID.
 
 Returns:
- - []byte - a JSON marshalled version of the member list.
+ - []byte - JSON marshalled [group.Membership], which is an array of
+   [group.Member].
+
+Example JSON [group.Membership] return:
+ [
+   {
+     "ID": "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID",
+     "DhKey": {
+       "Value": 3534334367214237261,
+       "Fingerprint": 16801541511233098363
+     }
+   },
+   {
+     "ID": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+     "DhKey": {
+       "Value": 7497468244883513247,
+       "Fingerprint": 16801541511233098363
+     }
+   }
+ ]
  */
 - (NSData* _Nullable)getMembership:(NSError* _Nullable* _Nullable)error;
 /**
diff --git a/Frameworks/Bindings.xcframework/ios-arm64_x86_64-simulator/Bindings.framework/Versions/A/Bindings b/Frameworks/Bindings.xcframework/ios-arm64_x86_64-simulator/Bindings.framework/Versions/A/Bindings
index d8ecef8868deb6bd74c6e6ff23c6a72fb1d377e5..4f732858669f4204798186a99b8dd9687ff7b788 100644
Binary files a/Frameworks/Bindings.xcframework/ios-arm64_x86_64-simulator/Bindings.framework/Versions/A/Bindings and b/Frameworks/Bindings.xcframework/ios-arm64_x86_64-simulator/Bindings.framework/Versions/A/Bindings differ
diff --git a/Frameworks/Bindings.xcframework/ios-arm64_x86_64-simulator/Bindings.framework/Versions/A/Headers/Bindings.objc.h b/Frameworks/Bindings.xcframework/ios-arm64_x86_64-simulator/Bindings.framework/Versions/A/Headers/Bindings.objc.h
index 15e54413e58bd26f6498c353c161b67e8d7c92e5..40a89ee2ee4afde62d99dcdcac9ef77d09c7c663 100644
--- a/Frameworks/Bindings.xcframework/ios-arm64_x86_64-simulator/Bindings.framework/Versions/A/Headers/Bindings.objc.h
+++ b/Frameworks/Bindings.xcframework/ios-arm64_x86_64-simulator/Bindings.framework/Versions/A/Headers/Bindings.objc.h
@@ -1182,7 +1182,26 @@ the first contact is the leader/creator of the group.
 All subsequent members are ordered by their ID.
 
 Returns:
- - []byte - a JSON marshalled version of the member list.
+ - []byte - JSON marshalled [group.Membership], which is an array of
+   [group.Member].
+
+Example JSON [group.Membership] return:
+ [
+   {
+     "ID": "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID",
+     "DhKey": {
+       "Value": 3534334367214237261,
+       "Fingerprint": 16801541511233098363
+     }
+   },
+   {
+     "ID": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+     "DhKey": {
+       "Value": 7497468244883513247,
+       "Fingerprint": 16801541511233098363
+     }
+   }
+ ]
  */
 - (NSData* _Nullable)getMembership:(NSError* _Nullable* _Nullable)error;
 /**
diff --git a/Sources/XXClient/Group/Functors/GroupGetMembership.swift b/Sources/XXClient/Group/Functors/GroupGetMembership.swift
index 1d78a2486781187817b022a96741b12c8217cbf6..4df1694412ca0e82001c18ec53938f7855f6778b 100644
--- a/Sources/XXClient/Group/Functors/GroupGetMembership.swift
+++ b/Sources/XXClient/Group/Functors/GroupGetMembership.swift
@@ -2,9 +2,9 @@ import Bindings
 import XCTestDynamicOverlay
 
 public struct GroupGetMembership {
-  public var run: () throws -> Data
+  public var run: () throws -> [GroupMember]
 
-  public func callAsFunction() throws -> Data {
+  public func callAsFunction() throws -> [GroupMember] {
     try run()
   }
 }
@@ -12,7 +12,8 @@ public struct GroupGetMembership {
 extension GroupGetMembership {
   public static func live(_ bindingsGroup: BindingsGroup) -> GroupGetMembership {
     GroupGetMembership {
-      try bindingsGroup.getMembership()
+      let data = try bindingsGroup.getMembership()
+      return try [GroupMember].decode(data)
     }
   }
 }
diff --git a/Sources/XXClient/Helpers/ConvertJsonNumberToString.swift b/Sources/XXClient/Helpers/ConvertJsonNumberToString.swift
new file mode 100644
index 0000000000000000000000000000000000000000..293f1ca640c4c69fc3e3958329b51671ff6b3508
--- /dev/null
+++ b/Sources/XXClient/Helpers/ConvertJsonNumberToString.swift
@@ -0,0 +1,19 @@
+import Foundation
+
+func convertJsonNumberToString(
+  in input: Data,
+  at key: String
+) -> Data {
+  guard var string = String(data: input, encoding: .utf8) else {
+    return input
+  }
+  string = string.replacingOccurrences(
+    of: #""\#(key)"( *):( *)([0-9]+)( *)(,*)"#,
+    with: #""\#(key)"$1:$2"$3"$4$5"#,
+    options: [.regularExpression]
+  )
+  guard let output = string.data(using: .utf8) else {
+    return input
+  }
+  return output
+}
diff --git a/Sources/XXClient/Models/DHKey.swift b/Sources/XXClient/Models/DHKey.swift
new file mode 100644
index 0000000000000000000000000000000000000000..69380ede4069535867cfc0a65a3ca77c6fca5b1f
--- /dev/null
+++ b/Sources/XXClient/Models/DHKey.swift
@@ -0,0 +1,23 @@
+import Foundation
+
+public struct DHKey: Equatable {
+  public init(value: String, fingerprint: UInt64) {
+    self.value = value
+    self.fingerprint = fingerprint
+  }
+
+  public var value: String
+  public var fingerprint: UInt64
+}
+
+extension DHKey: Decodable {
+  enum CodingKeys: String, CodingKey {
+    case value = "Value"
+    case fingerprint = "Fingerprint"
+  }
+
+  public static func decode(_ data: Data) throws -> Self {
+    let data = convertJsonNumberToString(in: data, at: "Value")
+    return try JSONDecoder().decode(Self.self, from: data)
+  }
+}
diff --git a/Sources/XXClient/Models/GroupMember.swift b/Sources/XXClient/Models/GroupMember.swift
new file mode 100644
index 0000000000000000000000000000000000000000..b08d71c250c9af5d4c6ca504dda9fc8586117eb5
--- /dev/null
+++ b/Sources/XXClient/Models/GroupMember.swift
@@ -0,0 +1,30 @@
+import Foundation
+
+public struct GroupMember: Equatable {
+  public init(id: Data, dhKey: DHKey) {
+    self.id = id
+    self.dhKey = dhKey
+  }
+
+  public var id: Data
+  public var dhKey: DHKey
+}
+
+extension GroupMember: Decodable {
+  enum CodingKeys: String, CodingKey {
+    case id = "ID"
+    case dhKey = "DhKey"
+  }
+
+  public static func decode(_ data: Data) throws -> Self {
+    let data = convertJsonNumberToString(in: data, at: "Value")
+    return try JSONDecoder().decode(Self.self, from: data)
+  }
+}
+
+extension Array where Element == GroupMember {
+  public static func decode(_ data: Data) throws -> Self {
+    let data = convertJsonNumberToString(in: data, at: "Value")
+    return try JSONDecoder().decode(Self.self, from: data)
+  }
+}
diff --git a/Tests/XXClientTests/Helpers/ConvertJsonNumberToStringTests.swift b/Tests/XXClientTests/Helpers/ConvertJsonNumberToStringTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..db3a4b2edc77a81ae493a03b9294389ff7c6a203
--- /dev/null
+++ b/Tests/XXClientTests/Helpers/ConvertJsonNumberToStringTests.swift
@@ -0,0 +1,84 @@
+import CustomDump
+import XCTest
+@testable import XXClient
+
+final class ConvertJsonNumberToStringTests: XCTestCase {
+  func testConverting() {
+    assert(
+      input: #"{"number":1234567890,"text":"hello"}"#,
+      key: "number",
+      expected: #"{"number":"1234567890","text":"hello"}"#
+    )
+
+    assert(
+      input: #"{"text":"hello","number":1234567890}"#,
+      key: "number",
+      expected: #"{"text":"hello","number":"1234567890"}"#
+    )
+
+    assert(
+      input: #"{  "number"  :  1234567890  ,  "text"  :  "hello"  }"#,
+      key: "number",
+      expected: #"{  "number"  :  "1234567890"  ,  "text"  :  "hello"  }"#
+    )
+
+    assert(
+      input: #"{  "text"  :  "hello"  ,  "number"  :  1234567890  }"#,
+      key: "number",
+      expected: #"{  "text"  :  "hello"  ,  "number"  :  "1234567890"  }"#
+    )
+
+    assert(
+      input: """
+      {
+        "number": 1234567890,
+        "text": "hello"
+      }
+      """,
+      key: "number",
+      expected: """
+      {
+        "number": "1234567890",
+        "text": "hello"
+      }
+      """
+    )
+
+    assert(
+      input: """
+      {
+        "text": "hello",
+        "number": 1234567890
+      }
+      """,
+      key: "number",
+      expected: """
+      {
+        "text": "hello",
+        "number": "1234567890"
+      }
+      """
+    )
+  }
+}
+
+private func assert(
+  input: String,
+  key: String,
+  expected: String,
+  file: StaticString = #file,
+  line: UInt = #line
+) {
+  XCTAssertNoDifference(
+    String(
+      data: convertJsonNumberToString(
+        in: input.data(using: .utf8)!,
+        at: key
+      ),
+      encoding: .utf8
+    )!,
+    expected,
+    file: file,
+    line: line
+  )
+}
diff --git a/Tests/XXClientTests/Models/DHKeyTests.swift b/Tests/XXClientTests/Models/DHKeyTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..380d69edb5a1536c6277dbc82dd8b01f65388ca3
--- /dev/null
+++ b/Tests/XXClientTests/Models/DHKeyTests.swift
@@ -0,0 +1,23 @@
+import CustomDump
+import XCTest
+@testable import XXClient
+
+final class DHKeyTests: XCTestCase {
+  func testCoding() throws {
+    let value = "1759426033802606996617132861414734059978289057332806031357800676138355264622676606691435603603751978195460163638145821347601916259127578968570412642641025630452893097179266022832268525346700655861033031712000288680395716922501450233258587788020541937373196899001184700899008948530359980753630443486308876999029238453979779103124291315202352475056237021681172884599194016245219278368648568458514708567045834427853469072638665888791358582182353417065794210125797368093469194927663862565508608719835557592421245749381164023134450699040591219966988201315627676532245052123725278573237006510683695959381015415110970848376498637637944431576313526294020390694483472829278364602405292767170719547347485307956614210210673321959886410245334772057212077704024337636501108566655549055129066343309591274727538343075929837698653965640646190405582788894021694347212874155979958144038307500444865955516612526623220973497735316081265793063949"
+    let fingerprint: UInt64 = 15989433043166758754
+    let jsonString = """
+    {
+      "Value": \(value),
+      "Fingerprint": \(fingerprint)
+    }
+    """
+    let jsonData = jsonString.data(using: .utf8)!
+    let model = try DHKey.decode(jsonData)
+
+    XCTAssertNoDifference(model, DHKey(
+      value: value,
+      fingerprint: fingerprint
+    ))
+  }
+}
diff --git a/Tests/XXClientTests/Models/FactTests.swift b/Tests/XXClientTests/Models/FactTests.swift
index fbe588c534f2edf4a758e1fc32ee96ff789c4dd7..2ba1da9ac9da82e174cee504e8708bb6794e9a81 100644
--- a/Tests/XXClientTests/Models/FactTests.swift
+++ b/Tests/XXClientTests/Models/FactTests.swift
@@ -25,4 +25,17 @@ final class FactTests: XCTestCase {
 
     XCTAssertNoDifference(decodedModel, model)
   }
+
+  func testCodingArray() throws {
+    let models = [
+      Fact(fact: "abcd", type: 0),
+      Fact(fact: "efgh", type: 1),
+      Fact(fact: "ijkl", type: 2),
+    ]
+
+    let encodedModels = try models.encode()
+    let decodedModels = try [Fact].decode(encodedModels)
+
+    XCTAssertNoDifference(models, decodedModels)
+  }
 }
diff --git a/Tests/XXClientTests/Models/GroupMemberTests.swift b/Tests/XXClientTests/Models/GroupMemberTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..a682dfe97ca7c707845c678dca6cba006e4adf5a
--- /dev/null
+++ b/Tests/XXClientTests/Models/GroupMemberTests.swift
@@ -0,0 +1,36 @@
+import CustomDump
+import XCTest
+@testable import XXClient
+
+final class GroupMemberTests: XCTestCase {
+  func testCoding() throws {
+    let idB64 = "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID"
+    let dhKeyValue = "1759426033802606996617132861414734059978289057332806031357800676138355264622676606691435603603751978195460163638145821347601916259127578968570412642641025630452893097179266022832268525346700655861033031712000288680395716922501450233258587788020541937373196899001184700899008948530359980753630443486308876999029238453979779103124291315202352475056237021681172884599194016245219278368648568458514708567045834427853469072638665888791358582182353417065794210125797368093469194927663862565508608719835557592421245749381164023134450699040591219966988201315627676532245052123725278573237006510683695959381015415110970848376498637637944431576313526294020390694483472829278364602405292767170719547347485307956614210210673321959886410245334772057212077704024337636501108566655549055129066343309591274727538343075929837698653965640646190405582788894021694347212874155979958144038307500444865955516612526623220973497735316081265793063949"
+    let dhKeyFingerprint: UInt64 = 15989433043166758754
+    let jsonString = """
+    {
+      "ID": "\(idB64)",
+      "DhKey": {
+        "Value": \(dhKeyValue),
+        "Fingerprint": \(dhKeyFingerprint)
+      }
+    }
+    """
+    let jsonData = jsonString.data(using: .utf8)!
+    let model = try GroupMember.decode(jsonData)
+
+    XCTAssertNoDifference(model, GroupMember(
+      id: Data(base64Encoded: idB64)!,
+      dhKey: DHKey(
+        value: dhKeyValue,
+        fingerprint: dhKeyFingerprint
+      )
+    ))
+
+    let jsonArrayString = "[\(jsonString)]"
+    let jsonArrayData = jsonArrayString.data(using: .utf8)!
+    let decodedModels = try [GroupMember].decode(jsonArrayData)
+
+    XCTAssertNoDifference(decodedModels, [model])
+  }
+}