diff --git a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopApplicationService.java b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopApplicationService.java
index 79841b80d0..ac7219caa7 100644
--- a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopApplicationService.java
+++ b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopApplicationService.java
@@ -231,7 +231,9 @@ public DesktopApplicationService(String[] args, ShutDownHandler shutDownHandler)
                 networkService,
                 userService,
                 bondedRolesService,
-                chatService);
+                chatService,
+                supportService,
+                tradeService);
     }
 
     @Override
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/open_trades/trade_state/TradeStateController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/open_trades/trade_state/TradeStateController.java
index 64cd410da1..486b9c9da4 100644
--- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/open_trades/trade_state/TradeStateController.java
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/open_trades/trade_state/TradeStateController.java
@@ -169,7 +169,7 @@ public void onActivate() {
                             PriceSpecFormatter.getFormattedPriceSpec(bisqEasyTrade.getOffer().getPriceSpec())));
             model.getSellerPriceDescriptionApprovalOverlay().set(
                     Res.get("bisqEasy.tradeState.acceptOrRejectSellersPrice.description.sellersPrice",
-                            PriceSpecFormatter.getFormattedPriceSpec(bisqEasyTrade.getContract().getAgreedPriceSpec())));
+                            PriceSpecFormatter.getFormattedPriceSpec(bisqEasyTrade.getContract().getPriceSpec())));
         });
     }
 
@@ -526,7 +526,7 @@ && requiresSellerPriceAcceptance()
 
     private boolean requiresSellerPriceAcceptance() {
         PriceSpec buyerPriceSpec = model.getBisqEasyTrade().get().getOffer().getPriceSpec();
-        PriceSpec sellerPriceSpec = model.getBisqEasyTrade().get().getContract().getAgreedPriceSpec();
+        PriceSpec sellerPriceSpec = model.getBisqEasyTrade().get().getContract().getPriceSpec();
         boolean priceSpecChanged = !buyerPriceSpec.equals(sellerPriceSpec);
 
         Set<BisqEasyTradeState> validStatesToRejectPrice = Set.of(
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/review/TakeOfferReviewController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/review/TakeOfferReviewController.java
index 73065fe025..02bad935d0 100644
--- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/review/TakeOfferReviewController.java
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/review/TakeOfferReviewController.java
@@ -125,14 +125,11 @@ public void init(BisqEasyOffer bisqEasyOffer) {
                     .ifPresent(model::setTakersQuoteSideAmount);
         }
 
-        PriceSpec priceSpec = bisqEasyOffer.getPriceSpec();
-        model.setSellersPriceSpec(priceSpec);
-
         Optional<PriceQuote> priceQuote = PriceUtil.findQuote(marketPriceService, bisqEasyOffer);
         priceQuote.ifPresent(priceInput::setQuote);
 
         applyPriceQuote(priceQuote);
-        applyPriceDetails(priceSpec, market);
+        applyPriceDetails(bisqEasyOffer.getPriceSpec(), market);
     }
 
     public void setTakersBaseSideAmount(Monetary amount) {
@@ -192,7 +189,7 @@ private void doTakeOffer(BisqEasyOffer bisqEasyOffer, UserIdentity takerIdentity
         Monetary takersQuoteSideAmount = model.getTakersQuoteSideAmount();
         BitcoinPaymentMethodSpec bitcoinPaymentMethodSpec = model.getBitcoinPaymentMethodSpec();
         FiatPaymentMethodSpec fiatPaymentMethodSpec = model.getFiatPaymentMethodSpec();
-        PriceSpec sellersPriceSpec = model.getSellersPriceSpec();
+        PriceSpec priceSpec = bisqEasyOffer.getPriceSpec();
         long marketPrice = model.getMarketPrice();
         BisqEasyProtocol bisqEasyProtocol = bisqEasyTradeService.createBisqEasyProtocol(takerIdentity.getIdentity(),
                 bisqEasyOffer,
@@ -201,7 +198,7 @@ private void doTakeOffer(BisqEasyOffer bisqEasyOffer, UserIdentity takerIdentity
                 bitcoinPaymentMethodSpec,
                 fiatPaymentMethodSpec,
                 mediator,
-                sellersPriceSpec,
+                priceSpec,
                 marketPrice);
         BisqEasyTrade bisqEasyTrade = bisqEasyProtocol.getModel();
         log.info("Selected mediator for trade {}: {}", bisqEasyTrade.getShortId(), mediator.map(UserProfile::getUserName).orElse("N/A"));
@@ -335,8 +332,7 @@ private void applyPriceDetails(PriceSpec priceSpec, Market market) {
         marketPrice.ifPresent(price -> model.setMarketPrice(price.getPriceQuote().getValue()));
         Optional<PriceQuote> marketPriceQuote = marketPrice.map(MarketPrice::getPriceQuote);
         String marketPriceAsString = marketPriceQuote.map(PriceFormatter::formatWithCode).orElse(Res.get("data.na"));
-        Optional<Double> percentFromMarketPrice;
-        percentFromMarketPrice = PriceUtil.findPercentFromMarketPrice(marketPriceService, priceSpec, market);
+        Optional<Double> percentFromMarketPrice = PriceUtil.findPercentFromMarketPrice(marketPriceService, priceSpec, market);
         double percent = percentFromMarketPrice.orElse(0d);
         if ((priceSpec instanceof FloatPriceSpec || priceSpec instanceof MarketPriceSpec) && percent == 0) {
             model.setPriceDetails(Res.get("bisqEasy.tradeWizard.review.priceDetails", marketPriceAsString));
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/review/TakeOfferReviewModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/review/TakeOfferReviewModel.java
index 49d03a3c86..117c8d940e 100644
--- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/review/TakeOfferReviewModel.java
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/take_offer/review/TakeOfferReviewModel.java
@@ -22,7 +22,6 @@
 import bisq.offer.bisq_easy.BisqEasyOffer;
 import bisq.offer.payment_method.BitcoinPaymentMethodSpec;
 import bisq.offer.payment_method.FiatPaymentMethodSpec;
-import bisq.offer.price.spec.PriceSpec;
 import bisq.trade.bisq_easy.BisqEasyTrade;
 import bisq.user.profile.UserProfile;
 import javafx.beans.property.ObjectProperty;
@@ -50,8 +49,6 @@ class TakeOfferReviewModel implements Model {
     private Monetary takersBaseSideAmount;
     @Setter
     private Monetary takersQuoteSideAmount;
-    @Setter
-    private PriceSpec sellersPriceSpec;
     private final ObjectProperty<TakeOfferStatus> takeOfferStatus = new SimpleObjectProperty<>(TakeOfferStatus.NOT_STARTED);
     @Setter
     private String price;
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/review/TradeWizardReviewController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/review/TradeWizardReviewController.java
index 548e872e44..4fe44c38a6 100644
--- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/review/TradeWizardReviewController.java
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/trade_wizard/review/TradeWizardReviewController.java
@@ -612,11 +612,10 @@ private void applyPriceDetails(PriceSpec priceSpec, Market market) {
         marketPrice.ifPresent(price -> model.setMarketPrice(price.getPriceQuote().getValue()));
         Optional<PriceQuote> marketPriceQuote = marketPriceService.findMarketPrice(market).map(MarketPrice::getPriceQuote);
         String marketPriceAsString = marketPriceQuote.map(PriceFormatter::formatWithCode).orElse(Res.get("data.na"));
-        Optional<Double> percentFromMarketPrice;
-        percentFromMarketPrice = PriceUtil.findPercentFromMarketPrice(marketPriceService, priceSpec, market);
+        Optional<Double> percentFromMarketPrice = PriceUtil.findPercentFromMarketPrice(marketPriceService, priceSpec, market);
         double percent = percentFromMarketPrice.orElse(0d);
         if ((priceSpec instanceof FloatPriceSpec || priceSpec instanceof MarketPriceSpec) && percent == 0) {
-            model.setPriceDetails(Res.get("bisqEasy.tradeWizard.review.priceDetails", marketPriceAsString));
+            model.setPriceDetails(Res.get("bisqEasy.tradeWizard.review.priceDetails"));
         } else {
             String aboveOrBelow = percent > 0 ? Res.get("offer.price.above") : Res.get("offer.price.below");
             String percentAsString = percentFromMarketPrice.map(Math::abs).map(PercentageFormatter::formatToPercentWithSymbol)
diff --git a/apps/http-api-app/src/main/java/bisq/http_api_node/HttpApiApplicationService.java b/apps/http-api-app/src/main/java/bisq/http_api_node/HttpApiApplicationService.java
index 11be8a4d84..13ac0db91c 100644
--- a/apps/http-api-app/src/main/java/bisq/http_api_node/HttpApiApplicationService.java
+++ b/apps/http-api-app/src/main/java/bisq/http_api_node/HttpApiApplicationService.java
@@ -169,7 +169,9 @@ public HttpApiApplicationService(String[] args) {
                 networkService,
                 userService,
                 bondedRolesService,
-                chatService);
+                chatService,
+                supportService,
+                tradeService);
     }
 
     @Override
diff --git a/build.gradle.kts b/build.gradle.kts
index 5c309ceec6..0e8c4cae07 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -10,17 +10,18 @@ tasks.register("buildAll") {
     doLast {
         listOf(
             "build",
-            ":wallets:build",
-            ":apps:seed-node-app:build",
-            ":apps:seed-node-app:installDist",
+            //":apps:seed-node-app:installDist",
+            ":apps:desktop:desktop:build",
             ":apps:desktop:desktop-app:build",
-            ":apps:desktop:desktop-app:installDist",
-            ":apps:desktop:desktop-app-launcher:generateInstallers",
+            ":apps:desktop:desktop-app-launcher:build",
+            //":apps:desktop:desktop-app:installDist",
+           // ":apps:desktop:desktop-app-launcher:generateInstallers",
             ":apps:desktop:webcam-app:build",
-            ":apps:oracle-node-app:build",
             ":apps:http-api-app:build",
             ":apps:node-monitor-web-app:build",
-//            ":REPLACEME:build",
+            ":apps:oracle-node-app:build",
+            ":apps:seed-node-app:build",
+            ":wallets:build",
         ).forEach {
             exec {
                 println("Executing Build: $it")
@@ -69,7 +70,6 @@ tasks.register("publishAll") {
         listOf(
             ":account:publishToMavenLocal",
             ":application:publishToMavenLocal",
-//            ":bisq-easy:publishToMavenLocal",
             ":bonded-roles:publishToMavenLocal",
             ":chat:publishToMavenLocal",
             ":common:publishToMavenLocal",
diff --git a/common/src/main/java/bisq/common/monetary/Coin.java b/common/src/main/java/bisq/common/monetary/Coin.java
index 3cd8ab4eec..7cd94b91bb 100644
--- a/common/src/main/java/bisq/common/monetary/Coin.java
+++ b/common/src/main/java/bisq/common/monetary/Coin.java
@@ -151,7 +151,7 @@ private Coin(double faceValue, String code, int precision) {
         super(code + " [crypto]", faceValue, code, precision, code.equals("BSQ") ? 2 : 4);
     }
 
-    private Coin(String id, long value, String code, int precision, int lowPrecision) {
+    public Coin(String id, long value, String code, int precision, int lowPrecision) {
         super(id, value, code, precision, lowPrecision);
     }
 
@@ -191,11 +191,6 @@ public Coin divide(long divisor) {
         return new Coin(this.value / divisor, this.code, this.precision);
     }
 
-    @Override
-    public double toDouble(long value) {
-        return MathUtils.roundDouble(BigDecimal.valueOf(value).movePointLeft(precision).doubleValue(), precision);
-    }
-
     private static int derivePrecision(String code) {
         if (code.equals("XMR")) return 12;
         if (code.equals("BSQ")) return 2;
@@ -204,7 +199,7 @@ private static int derivePrecision(String code) {
 
     public Coin round(int roundPrecision) {
         //todo (low prio) add tests
-        double rounded = MathUtils.roundDouble(toDouble(value), roundPrecision);
+        double rounded = MathUtils.roundDouble(asDouble(), roundPrecision);
         long shifted = BigDecimal.valueOf(rounded).movePointRight(precision).longValue();
         return Coin.fromValue(shifted, code, precision);
     }
diff --git a/common/src/main/java/bisq/common/monetary/Fiat.java b/common/src/main/java/bisq/common/monetary/Fiat.java
index e2d24dfad4..daefad2339 100644
--- a/common/src/main/java/bisq/common/monetary/Fiat.java
+++ b/common/src/main/java/bisq/common/monetary/Fiat.java
@@ -86,7 +86,7 @@ private Fiat(double faceValue, String code, int precision) {
         super(code, faceValue, code, precision, 2);
     }
 
-    private Fiat(String id, long value, String code, int precision, int lowPrecision) {
+    public Fiat(String id, long value, String code, int precision, int lowPrecision) {
         super(id, value, code, precision, lowPrecision);
     }
 
@@ -127,13 +127,8 @@ public Fiat divide(long divisor) {
         return new Fiat(this.value / divisor, this.code, this.precision);
     }
 
-    @Override
-    public double toDouble(long value) {
-        return MathUtils.roundDouble(BigDecimal.valueOf(value).movePointLeft(precision).doubleValue(), precision);
-    }
-
     public Fiat round(int roundPrecision) {
-        double rounded = MathUtils.roundDouble(toDouble(value), roundPrecision);
+        double rounded = MathUtils.roundDouble(asDouble(), roundPrecision);
         long shifted = BigDecimal.valueOf(rounded).movePointRight(precision).longValue();
         return Fiat.fromValue(shifted, code, precision);
     }
diff --git a/common/src/main/java/bisq/common/monetary/Monetary.java b/common/src/main/java/bisq/common/monetary/Monetary.java
index 279daebcf8..7fcc8e8de3 100644
--- a/common/src/main/java/bisq/common/monetary/Monetary.java
+++ b/common/src/main/java/bisq/common/monetary/Monetary.java
@@ -115,8 +115,9 @@ public static Monetary fromProto(bisq.common.protobuf.Monetary proto) {
         };
     }
 
-    public abstract double toDouble(long value);
-
+    public double toDouble(long value) {
+        return MathUtils.roundDouble(BigDecimal.valueOf(value).movePointLeft(precision).doubleValue(), precision);
+    }
     public double asDouble() {
         return toDouble(value);
     }
diff --git a/common/src/main/java/bisq/common/monetary/PriceQuote.java b/common/src/main/java/bisq/common/monetary/PriceQuote.java
index cbf9fc4623..b2e4b94d34 100644
--- a/common/src/main/java/bisq/common/monetary/PriceQuote.java
+++ b/common/src/main/java/bisq/common/monetary/PriceQuote.java
@@ -56,7 +56,7 @@ public final class PriceQuote implements Comparable<PriceQuote>, PersistableProt
     private final int lowPrecision;
     private final Market market;
 
-    private PriceQuote(long value, Monetary baseSideMonetary, Monetary quoteSideMonetary) {
+    public PriceQuote(long value, Monetary baseSideMonetary, Monetary quoteSideMonetary) {
         this.value = value;
         this.baseSideMonetary = baseSideMonetary;
         this.quoteSideMonetary = quoteSideMonetary;
diff --git a/contract/src/main/java/bisq/contract/bisq_easy/BisqEasyContract.java b/contract/src/main/java/bisq/contract/bisq_easy/BisqEasyContract.java
index 63149d25e9..82b8add9c0 100644
--- a/contract/src/main/java/bisq/contract/bisq_easy/BisqEasyContract.java
+++ b/contract/src/main/java/bisq/contract/bisq_easy/BisqEasyContract.java
@@ -43,7 +43,7 @@ public final class BisqEasyContract extends TwoPartyContract<BisqEasyOffer> {
     private final BitcoinPaymentMethodSpec baseSidePaymentMethodSpec;
     private final FiatPaymentMethodSpec quoteSidePaymentMethodSpec;
     private final Optional<UserProfile> mediator;
-    private final PriceSpec agreedPriceSpec;
+    private final PriceSpec priceSpec;
     private final long marketPrice;
     private final long takeOfferDate;
 
@@ -55,7 +55,7 @@ public BisqEasyContract(long takeOfferDate,
                             BitcoinPaymentMethodSpec baseSidePaymentMethodSpec,
                             FiatPaymentMethodSpec quoteSidePaymentMethodSpec,
                             Optional<UserProfile> mediator,
-                            PriceSpec agreedPriceSpec,
+                            PriceSpec priceSpec,
                             long marketPrice) {
         this(takeOfferDate,
                 offer,
@@ -66,7 +66,7 @@ public BisqEasyContract(long takeOfferDate,
                 baseSidePaymentMethodSpec,
                 quoteSidePaymentMethodSpec,
                 mediator,
-                agreedPriceSpec,
+                priceSpec,
                 marketPrice);
     }
 
@@ -79,7 +79,7 @@ private BisqEasyContract(long takeOfferDate,
                              BitcoinPaymentMethodSpec baseSidePaymentMethodSpec,
                              FiatPaymentMethodSpec quoteSidePaymentMethodSpec,
                              Optional<UserProfile> mediator,
-                             PriceSpec agreedPriceSpec,
+                             PriceSpec priceSpec,
                              long marketPrice) {
         super(takeOfferDate, offer, protocolType, taker);
         this.baseSideAmount = baseSideAmount;
@@ -87,7 +87,7 @@ private BisqEasyContract(long takeOfferDate,
         this.baseSidePaymentMethodSpec = baseSidePaymentMethodSpec;
         this.quoteSidePaymentMethodSpec = quoteSidePaymentMethodSpec;
         this.mediator = mediator;
-        this.agreedPriceSpec = agreedPriceSpec;
+        this.priceSpec = priceSpec;
         this.marketPrice = marketPrice;
         this.takeOfferDate = takeOfferDate;
 
@@ -120,7 +120,7 @@ private bisq.contract.protobuf.BisqEasyContract.Builder getBisqEasyContractBuild
                 .setQuoteSideAmount(quoteSideAmount)
                 .setBaseSidePaymentMethodSpec(baseSidePaymentMethodSpec.toProto(serializeForHash))
                 .setQuoteSidePaymentMethodSpec(quoteSidePaymentMethodSpec.toProto(serializeForHash))
-                .setAgreedPriceSpec(agreedPriceSpec.toProto(serializeForHash))
+                .setPriceSpec(priceSpec.toProto(serializeForHash))
                 .setMarketPrice(marketPrice);
         mediator.ifPresent(mediator -> builder.setMediator(mediator.toProto(serializeForHash)));
         return builder;
@@ -145,7 +145,7 @@ public static BisqEasyContract fromProto(bisq.contract.protobuf.Contract proto)
                 bisqEasyContractProto.hasMediator() ?
                         Optional.of(UserProfile.fromProto(bisqEasyContractProto.getMediator())) :
                         Optional.empty(),
-                PriceSpec.fromProto(bisqEasyContractProto.getAgreedPriceSpec()),
+                PriceSpec.fromProto(bisqEasyContractProto.getPriceSpec()),
                 bisqEasyContractProto.getMarketPrice());
     }
 }
diff --git a/contract/src/main/proto/contract.proto b/contract/src/main/proto/contract.proto
index 46f148c490..8ee495483c 100644
--- a/contract/src/main/proto/contract.proto
+++ b/contract/src/main/proto/contract.proto
@@ -83,7 +83,7 @@ message BisqEasyContract {
   offer.PaymentMethodSpec baseSidePaymentMethodSpec = 3;
   offer.PaymentMethodSpec quoteSidePaymentMethodSpec = 4;
   optional user.UserProfile mediator = 12;
-  offer.PriceSpec agreedPriceSpec = 13;
+  offer.PriceSpec priceSpec = 13;
   uint64 marketPrice = 14;
 }
 
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 207d57ad69..baa733f860 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -129,6 +129,8 @@ i2p-router = { module = 'net.i2p:router', version.ref = 'i2p-lib' }
 jackson-core = { module = 'com.fasterxml.jackson.core:jackson-core', version.ref = 'jackson-lib' }
 jackson-annotations = { module = 'com.fasterxml.jackson.core:jackson-annotations', version.ref = 'jackson-lib' }
 jackson-databind = { module = 'com.fasterxml.jackson.core:jackson-databind', version.ref = 'jackson-lib' }
+jackson-datatype = { module = 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8', version.ref = 'jackson-lib' }
+
 jakarta-websocket = { module = 'jakarta.websocket:jakarta.websocket-api', version.ref = 'jakarta-lib' }
 
 javacv = { module = "org.bytedeco:javacv-platform", version.ref = "javacv" }
@@ -177,13 +179,13 @@ glassfish-jersey = ['glassfish-jersey-jdk-http', 'glassfish-jersey-json-jackson'
 grpc = ['grpc-protobuf', 'grpc-services', 'grpc-stub']
 i2p = ['i2p-core', 'i2p-router', 'i2p-streaming']
 i2p-v2 = ['i2p-core-v2', 'i2p-streaming-v2']
-jackson = ['jackson-core', 'jackson-annotations', 'jackson-databind']
+jackson = ['jackson-core', 'jackson-annotations', 'jackson-databind', 'jackson-datatype']
 springfox-libs = ['springfox-boot-starter', 'springfox-swagger2', 'springfox-swagger-ui']
 rest-api-libs = ['swagger-jaxrs2-jakarta', 'glassfish-jersey-jdk-http', 'glassfish-jersey-json-jackson',
-    'glassfish-jersey-inject-hk2',
-    'glassfish-jaxb-runtime', 'jackson-core', 'jackson-annotations', 'jackson-databind']
+    'glassfish-jersey-inject-hk2', 'glassfish-jaxb-runtime',
+    'jackson-core', 'jackson-annotations', 'jackson-databind', 'jackson-datatype']
 websocket-libs = ['glassfish-jersey-json-jackson', 'glassfish-jersey-server', 'glassfish-jersey-containers-grizzly',
-    'glassfish-grizzly-websockets-server', 'jakarta-websocket', 'jackson-databind', 'swagger-swagger-annotations']
+    'glassfish-grizzly-websockets-server', 'jakarta-websocket', 'jackson-databind', 'jackson-datatype', 'swagger-swagger-annotations']
 
 # Referenced in subproject's build.gradle > plugin block as alias: `alias(libs.plugins.protobuf)`
 # Note: plugin version constraints are not supported by the java-platform plugin, so cannot be enforced there. However,
diff --git a/http-api/build.gradle.kts b/http-api/build.gradle.kts
index 958727cee6..1a2e91b7eb 100644
--- a/http-api/build.gradle.kts
+++ b/http-api/build.gradle.kts
@@ -30,6 +30,7 @@ dependencies {
     implementation("bisq:os-specific")
 
     implementation("network:network")
+    implementation("network:network-identity")
     implementation("bitcoind:core")
     implementation("wallets:wallet")
 
diff --git a/http-api/src/main/java/bisq/dto/DtoMappings.java b/http-api/src/main/java/bisq/dto/DtoMappings.java
new file mode 100644
index 0000000000..e7f6d36030
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/DtoMappings.java
@@ -0,0 +1,683 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto;
+
+import bisq.account.payment_method.BitcoinPaymentMethod;
+import bisq.account.payment_method.FiatPaymentMethod;
+import bisq.account.protocol_type.TradeProtocolType;
+import bisq.common.currency.Market;
+import bisq.common.encoding.Hex;
+import bisq.common.monetary.Coin;
+import bisq.common.monetary.Fiat;
+import bisq.common.monetary.Monetary;
+import bisq.common.monetary.PriceQuote;
+import bisq.common.network.Address;
+import bisq.common.network.AddressByTransportTypeMap;
+import bisq.common.network.TransportType;
+import bisq.dto.account.protocol_type.TradeProtocolTypeDto;
+import bisq.dto.common.currency.MarketDto;
+import bisq.dto.common.monetary.CoinDto;
+import bisq.dto.common.monetary.FiatDto;
+import bisq.dto.common.monetary.MonetaryDto;
+import bisq.dto.common.monetary.PriceQuoteDto;
+import bisq.dto.common.network.AddressByTransportTypeMapDto;
+import bisq.dto.common.network.AddressDto;
+import bisq.dto.common.network.TransportTypeDto;
+import bisq.dto.network.identity.NetworkIdDto;
+import bisq.dto.offer.DirectionDto;
+import bisq.dto.offer.amount.spec.*;
+import bisq.dto.offer.bisq_easy.BisqEasyOfferDto;
+import bisq.dto.offer.options.OfferOptionDto;
+import bisq.dto.offer.options.ReputationOptionDto;
+import bisq.dto.offer.options.TradeTermsOptionDto;
+import bisq.dto.offer.payment_method.BitcoinPaymentMethodSpecDto;
+import bisq.dto.offer.payment_method.FiatPaymentMethodSpecDto;
+import bisq.dto.offer.payment_method.PaymentMethodSpecDto;
+import bisq.dto.offer.price.spec.FixPriceSpecDto;
+import bisq.dto.offer.price.spec.FloatPriceSpecDto;
+import bisq.dto.offer.price.spec.MarketPriceSpecDto;
+import bisq.dto.offer.price.spec.PriceSpecDto;
+import bisq.dto.security.keys.KeyPairDto;
+import bisq.dto.security.keys.PrivateKeyDto;
+import bisq.dto.security.keys.PubKeyDto;
+import bisq.dto.security.keys.PublicKeyDto;
+import bisq.dto.security.pow.ProofOfWorkDto;
+import bisq.dto.user.profile.UserProfileDto;
+import bisq.dto.user.reputation.ReputationScoreDto;
+import bisq.network.identity.NetworkId;
+import bisq.offer.Direction;
+import bisq.offer.amount.spec.*;
+import bisq.offer.bisq_easy.BisqEasyOffer;
+import bisq.offer.options.OfferOption;
+import bisq.offer.options.ReputationOption;
+import bisq.offer.options.TradeTermsOption;
+import bisq.offer.payment_method.BitcoinPaymentMethodSpec;
+import bisq.offer.payment_method.FiatPaymentMethodSpec;
+import bisq.offer.payment_method.PaymentMethodSpec;
+import bisq.offer.payment_method.PaymentMethodSpecUtil;
+import bisq.offer.price.spec.FixPriceSpec;
+import bisq.offer.price.spec.FloatPriceSpec;
+import bisq.offer.price.spec.MarketPriceSpec;
+import bisq.offer.price.spec.PriceSpec;
+import bisq.security.DigestUtil;
+import bisq.security.keys.KeyGeneration;
+import bisq.security.keys.PubKey;
+import bisq.security.pow.ProofOfWork;
+import bisq.user.profile.UserProfile;
+import bisq.user.reputation.ReputationScore;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Base64;
+import java.util.stream.Collectors;
+
+public class DtoMappings {
+
+    // account.protocol_type
+
+    public static class TradeProtocolTypeMapping {
+        public static TradeProtocolType toPojo(TradeProtocolTypeDto dto) {
+            return switch (dto) {
+                case BISQ_EASY -> TradeProtocolType.BISQ_EASY;
+                case BISQ_MU_SIG -> TradeProtocolType.BISQ_MU_SIG;
+                case SUBMARINE -> TradeProtocolType.SUBMARINE;
+                case LIQUID_MU_SIG -> TradeProtocolType.LIQUID_MU_SIG;
+                case BISQ_LIGHTNING -> TradeProtocolType.BISQ_LIGHTNING;
+                case LIQUID_SWAP -> TradeProtocolType.LIQUID_SWAP;
+                case BSQ_SWAP -> TradeProtocolType.BSQ_SWAP;
+                case LIGHTNING_ESCROW -> TradeProtocolType.LIGHTNING_ESCROW;
+                case MONERO_SWAP -> TradeProtocolType.MONERO_SWAP;
+            };
+        }
+
+        public static TradeProtocolTypeDto from(TradeProtocolType value) {
+            return switch (value) {
+                case BISQ_EASY -> TradeProtocolTypeDto.BISQ_EASY;
+                case BISQ_MU_SIG -> TradeProtocolTypeDto.BISQ_MU_SIG;
+                case SUBMARINE -> TradeProtocolTypeDto.SUBMARINE;
+                case LIQUID_MU_SIG -> TradeProtocolTypeDto.LIQUID_MU_SIG;
+                case BISQ_LIGHTNING -> TradeProtocolTypeDto.BISQ_LIGHTNING;
+                case LIQUID_SWAP -> TradeProtocolTypeDto.LIQUID_SWAP;
+                case BSQ_SWAP -> TradeProtocolTypeDto.BSQ_SWAP;
+                case LIGHTNING_ESCROW -> TradeProtocolTypeDto.LIGHTNING_ESCROW;
+                case MONERO_SWAP -> TradeProtocolTypeDto.MONERO_SWAP;
+            };
+        }
+    }
+
+
+    // common.currency
+
+    public static class MarketMapping {
+        public static Market toPojo(MarketDto dto) {
+            return new Market(dto.baseCurrencyCode(), dto.quoteCurrencyCode(), dto.baseCurrencyName(), dto.quoteCurrencyName());
+        }
+
+        public static MarketDto from(Market value) {
+            return new MarketDto(value.getBaseCurrencyCode(), value.getQuoteCurrencyCode(), value.getBaseCurrencyName(), value.getQuoteCurrencyName());
+        }
+    }
+
+
+    // common.monetary
+
+    public static class CoinMapping {
+        public static Coin toPojo(CoinDto dto) {
+            return new Coin(dto.getId(), dto.getValue(), dto.getCode(), dto.getPrecision(), dto.getLowPrecision());
+        }
+
+        public static CoinDto from(Coin value) {
+            return new CoinDto(value.getId(), value.getValue(), value.getCode(), value.getPrecision(), value.getLowPrecision());
+        }
+    }
+
+    public static class FiatMapping {
+        public static Fiat toPojo(FiatDto dto) {
+            return new Fiat(dto.getId(), dto.getValue(), dto.getCode(), dto.getPrecision(), dto.getLowPrecision());
+        }
+
+        public static FiatDto from(Fiat value) {
+            return new FiatDto(value.getId(), value.getValue(), value.getCode(), value.getPrecision(), value.getLowPrecision());
+        }
+    }
+
+
+    public static class MonetaryMapping {
+        public static Monetary toPojo(MonetaryDto dto) {
+            if (dto instanceof FiatDto) {
+                return FiatMapping.toPojo((FiatDto) dto);
+            } else {
+                return CoinMapping.toPojo((CoinDto) dto);
+            }
+        }
+
+        public static MonetaryDto from(Monetary value) {
+            if (value instanceof Fiat) {
+                return new FiatDto(value.getId(), value.getValue(), value.getCode(), value.getPrecision(), value.getLowPrecision());
+            } else {
+                return new CoinDto(value.getId(), value.getValue(), value.getCode(), value.getPrecision(), value.getLowPrecision());
+            }
+        }
+    }
+
+    public static class PriceQuoteMapping {
+        public static PriceQuote toPojo(PriceQuoteDto dto) {
+            String baseCurrencyCode = dto.market().baseCurrencyCode();
+            String quoteCurrencyCode = dto.market().quoteCurrencyCode();
+            if (baseCurrencyCode.equals("BTC")) {
+                Monetary baseSideMonetary = Coin.asBtcFromFaceValue(1);
+                Monetary quoteSideMonetary = Fiat.from(dto.value(), quoteCurrencyCode);
+                return new PriceQuote(dto.value(), baseSideMonetary, quoteSideMonetary);
+            } else {
+                throw new UnsupportedOperationException("Altcoin price quote mapping is not supported yet");
+            }
+        }
+
+        public static PriceQuoteDto from(PriceQuote value) {
+            return new PriceQuoteDto(value.getValue(), MarketMapping.from(value.getMarket()));
+        }
+    }
+
+
+    // common.network
+
+    public static class AddressByTransportTypeMapMapping {
+        public static AddressByTransportTypeMap toPojo(AddressByTransportTypeMapDto dto) {
+            return new AddressByTransportTypeMap(dto.map().entrySet().stream().collect(Collectors.toMap(entry -> TransportTypeMapping.toPojo(entry.getKey()), entry -> AddressMapping.toPojo(entry.getValue()))));
+        }
+
+        public static AddressByTransportTypeMapDto from(AddressByTransportTypeMap map) {
+            return new AddressByTransportTypeMapDto(map.getMap().entrySet().stream().collect(Collectors.toMap(entry -> TransportTypeMapping.from(entry.getKey()), entry -> AddressMapping.from(entry.getValue()))));
+        }
+    }
+
+    public static class AddressMapping {
+        public static Address toPojo(AddressDto dto) {
+            return new Address(dto.host(), dto.port());
+        }
+
+        public static AddressDto from(Address value) {
+            return new AddressDto(value.getHost(), value.getPort());
+        }
+    }
+
+    public static class TransportTypeMapping {
+        public static TransportType toPojo(TransportTypeDto dto) {
+            if (dto == TransportTypeDto.CLEAR) {
+                return TransportType.CLEAR;
+            } else if (dto == TransportTypeDto.TOR) {
+                return TransportType.TOR;
+            } else if (dto == TransportTypeDto.I2P) {
+                return TransportType.I2P;
+            } else {
+                throw new IllegalArgumentException("Unsupported enum " + dto);
+            }
+        }
+
+        public static TransportTypeDto from(TransportType value) {
+            if (value == TransportType.CLEAR) {
+                return TransportTypeDto.CLEAR;
+            } else if (value == TransportType.TOR) {
+                return TransportTypeDto.TOR;
+            } else if (value == TransportType.I2P) {
+                return TransportTypeDto.I2P;
+            } else {
+                throw new IllegalArgumentException("Unsupported enum " + value);
+            }
+        }
+    }
+
+
+    // network.identity
+
+    public static class NetworkIdMapping {
+        public static NetworkId toPojo(NetworkIdDto dto) {
+            return new NetworkId(AddressByTransportTypeMapMapping.toPojo(dto.addressByTransportTypeMap()), PubKeyMapping.toPojo(dto.pubKey()));
+        }
+
+        public static NetworkIdDto from(NetworkId value) {
+            return new NetworkIdDto(AddressByTransportTypeMapMapping.from(value.getAddressByTransportTypeMap()), PubKeyMapping.from(value.getPubKey()));
+        }
+    }
+
+
+    // offer
+
+    public static class DirectionMapping {
+        public static Direction toPojo(DirectionDto dto) {
+            if (dto == DirectionDto.BUY) {
+                return Direction.BUY;
+            } else {
+                return Direction.SELL;
+            }
+        }
+
+        public static DirectionDto from(Direction value) {
+            if (value == Direction.BUY) {
+                return DirectionDto.BUY;
+            } else {
+                return DirectionDto.SELL;
+            }
+        }
+    }
+
+
+    // offer.amount.spec
+
+    public static class AmountSpecMapping {
+        public static AmountSpec toPojo(AmountSpecDto dto) {
+            if (dto instanceof RangeAmountSpecDto) {
+                return RangeAmountSpecMapping.toPojo((RangeAmountSpecDto) dto);
+            } else {
+                return FixedAmountSpecMapping.toPojo((FixedAmountSpecDto) dto);
+            }
+        }
+
+        public static AmountSpecDto from(AmountSpec value) {
+            if (value instanceof RangeAmountSpec) {
+                return RangeAmountSpecMapping.from((RangeAmountSpec) value);
+            } else {
+                return FixedAmountSpecMapping.from((FixedAmountSpec) value);
+            }
+        }
+    }
+
+    public static class BaseSideFixedAmountSpecMapping {
+        public static BaseSideFixedAmountSpec toPojo(BaseSideFixedAmountSpecDto dto) {
+            return new BaseSideFixedAmountSpec(dto.getAmount());
+        }
+
+        public static BaseSideFixedAmountSpecDto from(BaseSideFixedAmountSpec value) {
+            return new BaseSideFixedAmountSpecDto(value.getAmount());
+        }
+    }
+
+    public static class BaseSideRangeAmountSpecMapping {
+        public static BaseSideRangeAmountSpec toPojo(BaseSideRangeAmountSpecDto dto) {
+            return new BaseSideRangeAmountSpec(dto.getMinAmount(), dto.getMaxAmount());
+        }
+
+        public static BaseSideRangeAmountSpecDto from(BaseSideRangeAmountSpec value) {
+            return new BaseSideRangeAmountSpecDto(value.getMinAmount(), value.getMaxAmount());
+        }
+    }
+
+    public static class FixedAmountSpecMapping {
+        public static FixedAmountSpec toPojo(FixedAmountSpecDto dto) {
+            if (dto instanceof BaseSideFixedAmountSpecDto) {
+                return BaseSideFixedAmountSpecMapping.toPojo((BaseSideFixedAmountSpecDto) dto);
+            } else if (dto instanceof QuoteSideFixedAmountSpecDto) {
+                return QuoteSideFixedAmountSpecMapping.toPojo((QuoteSideFixedAmountSpecDto) dto);
+            } else {
+                throw new IllegalArgumentException("Unsupported FixedAmountSpecDto " + dto);
+            }
+        }
+
+        public static FixedAmountSpecDto from(FixedAmountSpec value) {
+            if (value instanceof BaseSideFixedAmountSpec) {
+                return BaseSideFixedAmountSpecMapping.from((BaseSideFixedAmountSpec) value);
+            } else if (value instanceof QuoteSideFixedAmountSpec) {
+                return QuoteSideFixedAmountSpecMapping.from((QuoteSideFixedAmountSpec) value);
+            } else {
+                throw new IllegalArgumentException("Unsupported FixedAmountSpec " + value);
+            }
+        }
+    }
+
+    public static class QuoteSideFixedAmountSpecMapping {
+        public static QuoteSideFixedAmountSpec toPojo(QuoteSideFixedAmountSpecDto dto) {
+            return new QuoteSideFixedAmountSpec(dto.getAmount());
+        }
+
+        public static QuoteSideFixedAmountSpecDto from(QuoteSideFixedAmountSpec value) {
+            return new QuoteSideFixedAmountSpecDto(value.getAmount());
+        }
+    }
+
+    public static class QuoteSideRangeAmountSpecMapping {
+        public static QuoteSideRangeAmountSpec toPojo(QuoteSideRangeAmountSpecDto dto) {
+            return new QuoteSideRangeAmountSpec(dto.getMinAmount(), dto.getMaxAmount());
+        }
+
+        public static QuoteSideRangeAmountSpecDto from(QuoteSideRangeAmountSpec value) {
+            return new QuoteSideRangeAmountSpecDto(value.getMinAmount(), value.getMaxAmount());
+        }
+    }
+
+    public static class RangeAmountSpecMapping {
+        public static RangeAmountSpec toPojo(RangeAmountSpecDto dto) {
+            if (dto instanceof BaseSideRangeAmountSpecDto) {
+                return BaseSideRangeAmountSpecMapping.toPojo((BaseSideRangeAmountSpecDto) dto);
+            } else if (dto instanceof QuoteSideRangeAmountSpecDto) {
+                return QuoteSideRangeAmountSpecMapping.toPojo((QuoteSideRangeAmountSpecDto) dto);
+            } else {
+                throw new IllegalArgumentException("Unsupported RangeAmountSpecDto " + dto);
+            }
+        }
+
+        public static RangeAmountSpecDto from(RangeAmountSpec value) {
+            if (value instanceof BaseSideRangeAmountSpec) {
+                return BaseSideRangeAmountSpecMapping.from((BaseSideRangeAmountSpec) value);
+            } else if (value instanceof QuoteSideRangeAmountSpec) {
+                return QuoteSideRangeAmountSpecMapping.from((QuoteSideRangeAmountSpec) value);
+            } else {
+                throw new IllegalArgumentException("Unsupported RangeAmountSpec " + value);
+            }
+        }
+    }
+
+
+    // offer.bisq_easy
+
+    public static class BisqEasyOfferMapping {
+        public static BisqEasyOffer toPojo(BisqEasyOfferDto dto) {
+            return new BisqEasyOffer(dto.id(), dto.date(), NetworkIdMapping.toPojo(dto.makerNetworkId()), DirectionMapping.toPojo(dto.direction()), MarketMapping.toPojo(dto.market()), AmountSpecMapping.toPojo(dto.amountSpec()), PriceSpecMapping.toPojo(dto.priceSpec()), dto.protocolTypes().stream().map(TradeProtocolTypeMapping::toPojo).collect(Collectors.toList()), dto.baseSidePaymentMethodSpecs().stream().map(BitcoinPaymentMethodSpecMapping::toPojo).collect(Collectors.toList()), dto.quoteSidePaymentMethodSpecs().stream().map(FiatPaymentMethodSpecMapping::toPojo).collect(Collectors.toList()), dto.offerOptions().stream().map(OfferOptionMapping::toPojo).collect(Collectors.toList()), dto.supportedLanguageCodes());
+        }
+
+        public static BisqEasyOfferDto from(BisqEasyOffer value) {
+            return new BisqEasyOfferDto(value.getId(), value.getDate(), NetworkIdMapping.from(value.getMakerNetworkId()), DirectionMapping.from(value.getDirection()), MarketMapping.from(value.getMarket()), AmountSpecMapping.from(value.getAmountSpec()), PriceSpecMapping.from(value.getPriceSpec()), value.getProtocolTypes().stream().map(TradeProtocolTypeMapping::from).collect(Collectors.toList()), value.getBaseSidePaymentMethodSpecs().stream().map(BitcoinPaymentMethodSpecMapping::from).collect(Collectors.toList()), value.getQuoteSidePaymentMethodSpecs().stream().map(FiatPaymentMethodSpecMapping::from).collect(Collectors.toList()), value.getOfferOptions().stream().map(OfferOptionMapping::from).collect(Collectors.toList()), value.getSupportedLanguageCodes());
+        }
+    }
+
+
+    // offer.options
+
+    public static class OfferOptionMapping {
+        public static OfferOption toPojo(OfferOptionDto dto) {
+            if (dto instanceof ReputationOptionDto) {
+                return ReputationOptionMapping.toPojo((ReputationOptionDto) dto);
+            } else if (dto instanceof TradeTermsOptionDto) {
+                return TradeTermsOptionMapping.toPojo((TradeTermsOptionDto) dto);
+            } else {
+                throw new IllegalArgumentException("Unsupported OfferOptionDto " + dto);
+            }
+        }
+
+        public static OfferOptionDto from(OfferOption value) {
+            if (value instanceof ReputationOption) {
+                //noinspection deprecation
+                return new ReputationOptionDto(((ReputationOption) value).getRequiredTotalReputationScore());
+            } else if (value instanceof TradeTermsOption) {
+                return new TradeTermsOptionDto(((TradeTermsOption) value).getMakersTradeTerms());
+            } else {
+                throw new IllegalArgumentException("Unsupported OfferOption " + value);
+            }
+        }
+    }
+
+    public static class ReputationOptionMapping {
+        public static ReputationOption toPojo(ReputationOptionDto dto) {
+            //noinspection deprecation
+            return new ReputationOption(dto.getRequiredTotalReputationScore());
+        }
+
+        public static ReputationOptionDto from(ReputationOption value) {
+            //noinspection deprecation
+            return new ReputationOptionDto(value.getRequiredTotalReputationScore());
+        }
+    }
+
+    public static class TradeTermsOptionMapping {
+        public static TradeTermsOption toPojo(TradeTermsOptionDto dto) {
+            return new TradeTermsOption(dto.getMakersTradeTerms());
+        }
+
+        public static TradeTermsOptionDto from(TradeTermsOption value) {
+            return new TradeTermsOptionDto(value.getMakersTradeTerms());
+        }
+    }
+
+
+    // offer.payment_method
+
+    public static class BitcoinPaymentMethodSpecMapping {
+        public static BitcoinPaymentMethodSpec toPojo(BitcoinPaymentMethodSpecDto dto) {
+            String paymentMethod = dto.getPaymentMethod();
+            BitcoinPaymentMethod method = PaymentMethodSpecUtil.getBitcoinPaymentMethod(paymentMethod);
+            return new BitcoinPaymentMethodSpec(method, dto.getSaltedMakerAccountId());
+        }
+
+        public static BitcoinPaymentMethodSpecDto from(BitcoinPaymentMethodSpec value) {
+            return new BitcoinPaymentMethodSpecDto(value.getPaymentMethod().getName(), value.getSaltedMakerAccountId());
+        }
+    }
+
+    public static class FiatPaymentMethodSpecMapping {
+        public static FiatPaymentMethodSpec toPojo(FiatPaymentMethodSpecDto dto) {
+            String paymentMethod = dto.getPaymentMethod();
+            FiatPaymentMethod method = PaymentMethodSpecUtil.getFiatPaymentMethod(paymentMethod);
+            return new FiatPaymentMethodSpec(method, dto.getSaltedMakerAccountId());
+        }
+
+        public static FiatPaymentMethodSpecDto from(FiatPaymentMethodSpec value) {
+            return new FiatPaymentMethodSpecDto(value.getPaymentMethod().getName(), value.getSaltedMakerAccountId());
+        }
+    }
+
+    public static class PaymentMethodSpecMapping {
+        public static PaymentMethodSpec<?> toPojo(PaymentMethodSpecDto dto) {
+            if (dto instanceof FiatPaymentMethodSpecDto) {
+                return FiatPaymentMethodSpecMapping.toPojo((FiatPaymentMethodSpecDto) dto);
+            } else if (dto instanceof BitcoinPaymentMethodSpecDto) {
+                return BitcoinPaymentMethodSpecMapping.toPojo((BitcoinPaymentMethodSpecDto) dto);
+            } else {
+                throw new IllegalArgumentException("Unsupported PaymentMethodSpecDto " + dto);
+            }
+        }
+
+        public static PaymentMethodSpecDto from(PaymentMethodSpec<?> value) {
+            if (value instanceof FiatPaymentMethodSpec) {
+                return FiatPaymentMethodSpecMapping.from((FiatPaymentMethodSpec) value);
+            } else if (value instanceof BitcoinPaymentMethodSpec) {
+                return BitcoinPaymentMethodSpecMapping.from((BitcoinPaymentMethodSpec) value);
+            } else {
+                throw new IllegalArgumentException("Unsupported PaymentMethodSpec " + value);
+            }
+        }
+    }
+
+
+    // offer.price.spec
+
+    public static class MarketPriceSpecMapping {
+        public static MarketPriceSpec toPojo(MarketPriceSpecDto dto) {
+            return new MarketPriceSpec();
+        }
+
+        public static MarketPriceSpecDto from(MarketPriceSpec value) {
+            return new MarketPriceSpecDto();
+        }
+    }
+
+    public static class FloatPriceSpecMapping {
+        public static FloatPriceSpec toPojo(FloatPriceSpecDto dto) {
+            return new FloatPriceSpec(dto.getPercentage());
+        }
+
+        public static FloatPriceSpecDto from(FloatPriceSpec value) {
+            return new FloatPriceSpecDto(value.getPercentage());
+        }
+    }
+
+    public static class FixPriceSpecMapping {
+        public static FixPriceSpec toPojo(FixPriceSpecDto dto) {
+            return new FixPriceSpec(PriceQuoteMapping.toPojo(dto.getPriceQuote()));
+        }
+
+        public static FixPriceSpecDto from(FixPriceSpec value) {
+            return new FixPriceSpecDto(PriceQuoteMapping.from(value.getPriceQuote()));
+        }
+    }
+
+    public static class PriceSpecMapping {
+        public static PriceSpec toPojo(PriceSpecDto dto) {
+            return switch (dto) {
+                case MarketPriceSpecDto marketPriceSpecDto -> MarketPriceSpecMapping.toPojo(marketPriceSpecDto);
+                case FixPriceSpecDto fixPriceSpecDto -> FixPriceSpecMapping.toPojo(fixPriceSpecDto);
+                case FloatPriceSpecDto floatPriceSpecDto -> FloatPriceSpecMapping.toPojo(floatPriceSpecDto);
+                case null, default -> throw new IllegalArgumentException("Unsupported PriceSpecDto " + dto);
+            };
+        }
+
+        public static PriceSpecDto from(PriceSpec value) {
+            return switch (value) {
+                case MarketPriceSpec marketPriceSpec -> MarketPriceSpecMapping.from(marketPriceSpec);
+                case FixPriceSpec fixPriceSpec -> FixPriceSpecMapping.from(fixPriceSpec);
+                case FloatPriceSpec floatPriceSpec -> FloatPriceSpecMapping.from(floatPriceSpec);
+                case null, default -> throw new IllegalArgumentException("Unsupported PriceSpec " + value);
+            };
+        }
+    }
+
+
+    // security.keys
+
+    public static class KeyPairDtoMapping {
+        public static KeyPair toPojo(KeyPairDto dto) {
+            PublicKey publicKey = PublicKeyMapping.toPojo(dto.publicKey());
+            PrivateKey privateKey = PrivateKeyMapping.toPojo(dto.privateKey());
+            return new KeyPair(publicKey, privateKey);
+        }
+
+        public static KeyPairDto from(KeyPair value) {
+            PrivateKeyDto privateKeyDto = PrivateKeyMapping.from(value.getPrivate());
+            PublicKeyDto publicKeyDto = PublicKeyMapping.from(value.getPublic());
+            return new KeyPairDto(publicKeyDto, privateKeyDto);
+        }
+    }
+
+    public static class PrivateKeyMapping {
+        public static PrivateKey toPojo(PrivateKeyDto dto) {
+            try {
+                byte[] decoded = Base64.getDecoder().decode(dto.encoded());
+                return KeyGeneration.generatePrivate(decoded);
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to generate privateKey", e);
+            }
+        }
+
+        public static PrivateKeyDto from(PrivateKey value) {
+            return new PrivateKeyDto(Base64.getEncoder().encodeToString(value.getEncoded()));
+        }
+    }
+
+    public static class PubKeyMapping {
+        public static PubKey toPojo(PubKeyDto dto) {
+            return new PubKey(PublicKeyMapping.toPojo(dto.publicKey()), dto.keyId());
+        }
+
+        public static PubKeyDto from(PubKey value) {
+            PublicKey publicKey = value.getPublicKey();
+            PublicKeyDto publicKeyDto = PublicKeyMapping.from(publicKey);
+            String keyId = value.getKeyId();
+            byte[] hashAsBytes = DigestUtil.hash(publicKey.getEncoded());
+            String hash = Base64.getEncoder().encodeToString(hashAsBytes);
+            String id = Hex.encode(hashAsBytes);
+            return new PubKeyDto(publicKeyDto, keyId, hash, id);
+        }
+    }
+
+    public static class PublicKeyMapping {
+        public static PublicKey toPojo(PublicKeyDto dto) {
+            try {
+                byte[] decoded = Base64.getDecoder().decode(dto.encoded());
+                return KeyGeneration.generatePublic(decoded);
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to generate publicKey", e);
+            }
+        }
+
+        public static PublicKeyDto from(PublicKey value) {
+            return new PublicKeyDto(Base64.getEncoder().encodeToString(value.getEncoded()));
+        }
+    }
+
+
+    // security.pow
+
+    public static class ProofOfWorkDtoMapping {
+        public static ProofOfWork toPojo(ProofOfWorkDto dto) {
+            return new ProofOfWork(
+                    Base64.getDecoder().decode(dto.payload()),
+                    dto.counter(),
+                    dto.challenge() != null ? Base64.getDecoder().decode(dto.challenge()) : null,
+                    dto.difficulty(),
+                    Base64.getDecoder().decode(dto.solution()),
+                    dto.duration()
+            );
+        }
+
+        public static ProofOfWorkDto from(ProofOfWork value) {
+            return new ProofOfWorkDto(
+                    Base64.getEncoder().encodeToString(value.getPayload()),
+                    value.getCounter(),
+                    value.getChallenge() != null ? Base64.getEncoder().encodeToString(value.getChallenge()) : null,
+                    value.getDifficulty(),
+                    Base64.getEncoder().encodeToString(value.getSolution()),
+                    value.getDuration()
+            );
+        }
+    }
+
+
+    // user.profile
+
+    public static class UserProfileDtoMapping {
+        public static UserProfile toPojo(UserProfileDto dto) {
+            return new UserProfile(dto.version(),
+                    dto.nickName(),
+                    ProofOfWorkDtoMapping.toPojo(dto.proofOfWork()),
+                    dto.avatarVersion(),
+                    NetworkIdMapping.toPojo(dto.networkId()),
+                    dto.terms(),
+                    dto.statement(),
+                    dto.applicationVersion()
+            );
+        }
+
+        public static UserProfileDto from(UserProfile value) {
+            return new UserProfileDto(
+                    value.getVersion(),
+                    value.getNickName(),
+                    ProofOfWorkDtoMapping.from(value.getProofOfWork()),
+                    value.getAvatarVersion(),
+                    NetworkIdMapping.from(value.getNetworkId()),
+                    value.getTerms(),
+                    value.getStatement(),
+                    value.getApplicationVersion(),
+                    value.getNym(),
+                    value.getUserName(),
+                    value.getPublishDate()
+            );
+        }
+    }
+
+
+    // user.reputation
+
+    public static class ReputationScoreMapping {
+        public static ReputationScore toPojo(ReputationScoreDto dto) {
+            return new ReputationScore(dto.totalScore(), dto.fiveSystemScore(), dto.ranking());
+        }
+
+        public static ReputationScoreDto from(ReputationScore value) {
+            return new ReputationScoreDto(value.getTotalScore(), value.getFiveSystemScore(), value.getRanking());
+        }
+    }
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/OfferListItemDtoFactory.java b/http-api/src/main/java/bisq/dto/OfferListItemDtoFactory.java
new file mode 100644
index 0000000000..6f5becf4a4
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/OfferListItemDtoFactory.java
@@ -0,0 +1,123 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto;
+
+
+import bisq.account.payment_method.PaymentMethod;
+import bisq.bonded_roles.market_price.MarketPriceService;
+import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookMessage;
+import bisq.common.currency.Market;
+import bisq.dto.offer.bisq_easy.BisqEasyOfferDto;
+import bisq.dto.offer.bisq_easy.OfferListItemDto;
+import bisq.dto.user.reputation.ReputationScoreDto;
+import bisq.i18n.Res;
+import bisq.offer.Direction;
+import bisq.offer.amount.OfferAmountFormatter;
+import bisq.offer.amount.spec.AmountSpec;
+import bisq.offer.amount.spec.RangeAmountSpec;
+import bisq.offer.bisq_easy.BisqEasyOffer;
+import bisq.offer.payment_method.PaymentMethodSpecUtil;
+import bisq.offer.price.PriceUtil;
+import bisq.offer.price.spec.PriceSpec;
+import bisq.offer.price.spec.PriceSpecFormatter;
+import bisq.presentation.formatters.DateFormatter;
+import bisq.presentation.formatters.PriceFormatter;
+import bisq.user.identity.UserIdentityService;
+import bisq.user.profile.UserProfile;
+import bisq.user.profile.UserProfileService;
+import bisq.user.reputation.ReputationScore;
+import bisq.user.reputation.ReputationService;
+
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class OfferListItemDtoFactory {
+    public static OfferListItemDto createOfferListItemDto(UserProfileService userProfileService,
+                                                          UserIdentityService userIdentityService,
+                                                          ReputationService reputationService,
+                                                          MarketPriceService marketPriceService,
+                                                          BisqEasyOfferbookMessage bisqEasyOfferbookMessage) {
+        BisqEasyOffer bisqEasyOffer = bisqEasyOfferbookMessage.getBisqEasyOffer().orElseThrow();
+        boolean isMyOffer = bisqEasyOfferbookMessage.isMyMessage(userIdentityService);
+        Direction direction = bisqEasyOffer.getDirection();
+        String messageId = bisqEasyOfferbookMessage.getId();
+        String offerId = bisqEasyOffer.getId();
+        BisqEasyOfferDto bisqEasyOfferDto = DtoMappings.BisqEasyOfferMapping.from(bisqEasyOffer);
+        String authorUserProfileId = bisqEasyOfferbookMessage.getAuthorUserProfileId();
+        Optional<UserProfile> senderUserProfile = userProfileService.findUserProfile(authorUserProfileId);
+        String nym = senderUserProfile.map(UserProfile::getNym).orElse("");
+        String userName = senderUserProfile.map(UserProfile::getUserName).orElse("");
+        ReputationScoreDto reputationScore = senderUserProfile.flatMap(reputationService::findReputationScore)
+                .map(DtoMappings.ReputationScoreMapping::from)
+                .orElse(DtoMappings.ReputationScoreMapping.from(ReputationScore.NONE));
+
+        // For now, we send also the formatted values as we have not the complex formatters in mobile impl. yet.
+        // We might need to replicate the formatters anyway later and then those fields could be removed
+        long date = bisqEasyOfferbookMessage.getDate();
+        String formattedDate = DateFormatter.formatDateTime(new Date(date), DateFormat.MEDIUM, DateFormat.SHORT,
+                true, " " + Res.get("temporal.at") + " ");
+        AmountSpec amountSpec = bisqEasyOffer.getAmountSpec();
+        PriceSpec priceSpec = bisqEasyOffer.getPriceSpec();
+        boolean hasAmountRange = amountSpec instanceof RangeAmountSpec;
+        Market market = bisqEasyOffer.getMarket();
+        String formattedQuoteAmount = OfferAmountFormatter.formatQuoteAmount(
+                marketPriceService,
+                amountSpec,
+                priceSpec,
+                market,
+                hasAmountRange,
+                true
+        );
+        String formattedBaseAmount = OfferAmountFormatter.formatBaseAmount(
+                marketPriceService,
+                amountSpec,
+                priceSpec,
+                market,
+                hasAmountRange,
+                true,
+                false
+        );
+        String formattedPrice = PriceUtil.findQuote(marketPriceService, bisqEasyOffer)
+                .map(PriceFormatter::format)
+                .orElse("");
+        String formattedPriceSpec = PriceSpecFormatter.getFormattedPriceSpec(priceSpec, true);
+        List<String> quoteSidePaymentMethods = PaymentMethodSpecUtil.getPaymentMethods(bisqEasyOffer.getQuoteSidePaymentMethodSpecs())
+                .stream()
+                .map(PaymentMethod::getName)
+                .collect(Collectors.toList());
+        List<String> baseSidePaymentMethods = PaymentMethodSpecUtil.getPaymentMethods(bisqEasyOffer.getBaseSidePaymentMethodSpecs())
+                .stream()
+                .map(PaymentMethod::getName)
+                .collect(Collectors.toList());
+        return new OfferListItemDto(bisqEasyOfferDto,
+                isMyOffer,
+                nym,
+                userName,
+                reputationScore,
+                formattedDate,
+                formattedQuoteAmount,
+                formattedBaseAmount,
+                formattedPrice,
+                formattedPriceSpec,
+                quoteSidePaymentMethods,
+                baseSidePaymentMethods);
+    }
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/account/protocol_type/TradeProtocolTypeDto.java b/http-api/src/main/java/bisq/dto/account/protocol_type/TradeProtocolTypeDto.java
new file mode 100644
index 0000000000..10656f2be3
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/account/protocol_type/TradeProtocolTypeDto.java
@@ -0,0 +1,30 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.account.protocol_type;
+
+public enum TradeProtocolTypeDto {
+    BISQ_EASY,
+    BISQ_MU_SIG,
+    SUBMARINE,
+    LIQUID_MU_SIG,
+    BISQ_LIGHTNING,
+    LIQUID_SWAP,
+    BSQ_SWAP,
+    LIGHTNING_ESCROW,
+    MONERO_SWAP;
+}
diff --git a/http-api/src/main/java/bisq/dto/common/currency/MarketDto.java b/http-api/src/main/java/bisq/dto/common/currency/MarketDto.java
new file mode 100644
index 0000000000..35fa64a41b
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/common/currency/MarketDto.java
@@ -0,0 +1,24 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.common.currency;
+
+public record MarketDto(String baseCurrencyCode,
+                        String quoteCurrencyCode,
+                        String baseCurrencyName,
+                        String quoteCurrencyName) {
+}
diff --git a/http-api/src/main/java/bisq/dto/common/monetary/CoinDto.java b/http-api/src/main/java/bisq/dto/common/monetary/CoinDto.java
new file mode 100644
index 0000000000..a5b2c22a92
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/common/monetary/CoinDto.java
@@ -0,0 +1,38 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.common.monetary;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public final class CoinDto extends MonetaryDto {
+    @JsonCreator
+    public CoinDto(@JsonProperty("id") String id,
+                   @JsonProperty("value") long value,
+                   @JsonProperty("code") String code,
+                   @JsonProperty("precision") int precision,
+                   @JsonProperty("lowPrecision") int lowPrecision) {
+        super(id, value, code, precision, lowPrecision);
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/common/monetary/FiatDto.java b/http-api/src/main/java/bisq/dto/common/monetary/FiatDto.java
new file mode 100644
index 0000000000..ac1c0edaf3
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/common/monetary/FiatDto.java
@@ -0,0 +1,38 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.common.monetary;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@ToString
+@EqualsAndHashCode(callSuper = true)
+public class FiatDto extends MonetaryDto {
+    @JsonCreator
+    public FiatDto(@JsonProperty("id") String id,
+                   @JsonProperty("value") long value,
+                   @JsonProperty("code") String code,
+                   @JsonProperty("precision") int precision,
+                   @JsonProperty("lowPrecision") int lowPrecision) {
+        super(id, value, code, precision, lowPrecision);
+    }
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/common/monetary/MonetaryDto.java b/http-api/src/main/java/bisq/dto/common/monetary/MonetaryDto.java
new file mode 100644
index 0000000000..bdbf337832
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/common/monetary/MonetaryDto.java
@@ -0,0 +1,50 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.common.monetary;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+@JsonTypeInfo(
+        use = JsonTypeInfo.Id.NAME,
+        include = JsonTypeInfo.As.PROPERTY,
+        property = "type"
+)
+@JsonSubTypes({
+        @JsonSubTypes.Type(value = CoinDto.class, name = "Coin"),
+        @JsonSubTypes.Type(value = FiatDto.class, name = "Fiat"),
+})
+@EqualsAndHashCode
+@Getter
+public abstract class MonetaryDto {
+    protected final String id;
+    protected final long value;
+    protected final String code;
+    protected final int precision;
+    protected final int lowPrecision;
+
+    protected MonetaryDto(String id, long value, String code, int precision, int lowPrecision) {
+        this.id = id;
+        this.value = value;
+        this.code = code;
+        this.precision = precision;
+        this.lowPrecision = lowPrecision;
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/common/monetary/PriceQuoteDto.java b/http-api/src/main/java/bisq/dto/common/monetary/PriceQuoteDto.java
new file mode 100644
index 0000000000..aa03ed93b6
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/common/monetary/PriceQuoteDto.java
@@ -0,0 +1,23 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.common.monetary;
+
+import bisq.dto.common.currency.MarketDto;
+
+public record PriceQuoteDto(long value, MarketDto market) {
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/common/network/AddressByTransportTypeMapDto.java b/http-api/src/main/java/bisq/dto/common/network/AddressByTransportTypeMapDto.java
new file mode 100644
index 0000000000..1f3b125dae
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/common/network/AddressByTransportTypeMapDto.java
@@ -0,0 +1,23 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.common.network;
+
+import java.util.Map;
+
+public record AddressByTransportTypeMapDto(Map<TransportTypeDto, AddressDto> map) {
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/common/network/AddressDto.java b/http-api/src/main/java/bisq/dto/common/network/AddressDto.java
new file mode 100644
index 0000000000..0f0803257f
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/common/network/AddressDto.java
@@ -0,0 +1,21 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.common.network;
+
+public record AddressDto(String host, int port) {
+}
diff --git a/http-api/src/main/java/bisq/dto/common/network/TransportTypeDto.java b/http-api/src/main/java/bisq/dto/common/network/TransportTypeDto.java
new file mode 100644
index 0000000000..afb2bb30b6
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/common/network/TransportTypeDto.java
@@ -0,0 +1,24 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.common.network;
+
+public enum TransportTypeDto {
+    TOR,
+    I2P,
+    CLEAR;
+}
diff --git a/http-api/src/main/java/bisq/dto/network/identity/NetworkIdDto.java b/http-api/src/main/java/bisq/dto/network/identity/NetworkIdDto.java
new file mode 100644
index 0000000000..bf94bf878a
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/network/identity/NetworkIdDto.java
@@ -0,0 +1,25 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.network.identity;
+
+
+import bisq.dto.common.network.AddressByTransportTypeMapDto;
+import bisq.dto.security.keys.PubKeyDto;
+
+public record NetworkIdDto(AddressByTransportTypeMapDto addressByTransportTypeMap, PubKeyDto pubKey) {
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/offer/DirectionDto.java b/http-api/src/main/java/bisq/dto/offer/DirectionDto.java
new file mode 100644
index 0000000000..4d8a9ffde0
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/DirectionDto.java
@@ -0,0 +1,23 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer;
+
+public enum DirectionDto {
+    BUY,
+    SELL;
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/amount/spec/AmountSpecDto.java b/http-api/src/main/java/bisq/dto/offer/amount/spec/AmountSpecDto.java
new file mode 100644
index 0000000000..443b454aba
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/amount/spec/AmountSpecDto.java
@@ -0,0 +1,42 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.amount.spec;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+@JsonTypeInfo(
+        use = JsonTypeInfo.Id.NAME,
+        include = JsonTypeInfo.As.PROPERTY,
+        property = "type"
+)
+@JsonSubTypes({
+        @JsonSubTypes.Type(value = BaseSideFixedAmountSpecDto.class, name = "BaseSideFixedAmountSpec"),
+        @JsonSubTypes.Type(value = BaseSideRangeAmountSpecDto.class, name = "BaseSideRangeAmountSpec"),
+        @JsonSubTypes.Type(value = QuoteSideFixedAmountSpecDto.class, name = "QuoteSideFixedAmountSpec"),
+        @JsonSubTypes.Type(value = QuoteSideRangeAmountSpecDto.class, name = "QuoteSideRangeAmountSpec")
+})
+@Getter
+@EqualsAndHashCode
+public abstract class AmountSpecDto {
+    protected AmountSpecDto() {
+    }
+}
+
diff --git a/http-api/src/main/java/bisq/dto/offer/amount/spec/BaseSideFixedAmountSpecDto.java b/http-api/src/main/java/bisq/dto/offer/amount/spec/BaseSideFixedAmountSpecDto.java
new file mode 100644
index 0000000000..3cb3c62ce5
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/amount/spec/BaseSideFixedAmountSpecDto.java
@@ -0,0 +1,34 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.amount.spec;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class BaseSideFixedAmountSpecDto extends FixedAmountSpecDto {
+    @JsonCreator
+    public BaseSideFixedAmountSpecDto(@JsonProperty("amount") long amount) {
+        super(amount);
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/amount/spec/BaseSideRangeAmountSpecDto.java b/http-api/src/main/java/bisq/dto/offer/amount/spec/BaseSideRangeAmountSpecDto.java
new file mode 100644
index 0000000000..87f9252f59
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/amount/spec/BaseSideRangeAmountSpecDto.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.amount.spec;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class BaseSideRangeAmountSpecDto extends RangeAmountSpecDto {
+    @JsonCreator
+    public BaseSideRangeAmountSpecDto(@JsonProperty("minAmount") long minAmount,
+                                      @JsonProperty("maxAmount") long maxAmount) {
+        super(minAmount, maxAmount);
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/amount/spec/FixedAmountSpecDto.java b/http-api/src/main/java/bisq/dto/offer/amount/spec/FixedAmountSpecDto.java
new file mode 100644
index 0000000000..7ae7366668
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/amount/spec/FixedAmountSpecDto.java
@@ -0,0 +1,32 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.amount.spec;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public abstract class FixedAmountSpecDto extends AmountSpecDto {
+    public long amount;
+
+    public FixedAmountSpecDto(long amount) {
+        super();
+        this.amount = amount;
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/amount/spec/QuoteSideFixedAmountSpecDto.java b/http-api/src/main/java/bisq/dto/offer/amount/spec/QuoteSideFixedAmountSpecDto.java
new file mode 100644
index 0000000000..44ca872380
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/amount/spec/QuoteSideFixedAmountSpecDto.java
@@ -0,0 +1,34 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.amount.spec;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class QuoteSideFixedAmountSpecDto extends FixedAmountSpecDto {
+    @JsonCreator
+    public QuoteSideFixedAmountSpecDto(@JsonProperty("amount") long amount) {
+        super(amount);
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/amount/spec/QuoteSideRangeAmountSpecDto.java b/http-api/src/main/java/bisq/dto/offer/amount/spec/QuoteSideRangeAmountSpecDto.java
new file mode 100644
index 0000000000..c881dec32e
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/amount/spec/QuoteSideRangeAmountSpecDto.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.amount.spec;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class QuoteSideRangeAmountSpecDto extends RangeAmountSpecDto {
+    @JsonCreator
+    public QuoteSideRangeAmountSpecDto(@JsonProperty("minAmount") long minAmount,
+                                       @JsonProperty("maxAmount") long maxAmount) {
+        super(minAmount, maxAmount);
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/amount/spec/RangeAmountSpecDto.java b/http-api/src/main/java/bisq/dto/offer/amount/spec/RangeAmountSpecDto.java
new file mode 100644
index 0000000000..b80975d562
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/amount/spec/RangeAmountSpecDto.java
@@ -0,0 +1,34 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.amount.spec;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public abstract class RangeAmountSpecDto extends AmountSpecDto {
+    protected final long minAmount;
+    protected final long maxAmount;
+
+    public RangeAmountSpecDto(long minAmount, long maxAmount) {
+        super();
+        this.minAmount = minAmount;
+        this.maxAmount = maxAmount;
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/bisq_easy/BisqEasyOfferDto.java b/http-api/src/main/java/bisq/dto/offer/bisq_easy/BisqEasyOfferDto.java
new file mode 100644
index 0000000000..02007548a9
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/bisq_easy/BisqEasyOfferDto.java
@@ -0,0 +1,44 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.bisq_easy;
+
+import bisq.dto.account.protocol_type.TradeProtocolTypeDto;
+import bisq.dto.common.currency.MarketDto;
+import bisq.dto.network.identity.NetworkIdDto;
+import bisq.dto.offer.DirectionDto;
+import bisq.dto.offer.amount.spec.AmountSpecDto;
+import bisq.dto.offer.options.OfferOptionDto;
+import bisq.dto.offer.payment_method.BitcoinPaymentMethodSpecDto;
+import bisq.dto.offer.payment_method.FiatPaymentMethodSpecDto;
+import bisq.dto.offer.price.spec.PriceSpecDto;
+
+import java.util.List;
+
+public record BisqEasyOfferDto(String id,
+                               long date,
+                               NetworkIdDto makerNetworkId,
+                               DirectionDto direction,
+                               MarketDto market,
+                               AmountSpecDto amountSpec,
+                               PriceSpecDto priceSpec,
+                               List<TradeProtocolTypeDto> protocolTypes,
+                               List<BitcoinPaymentMethodSpecDto> baseSidePaymentMethodSpecs,
+                               List<FiatPaymentMethodSpecDto> quoteSidePaymentMethodSpecs,
+                               List<OfferOptionDto> offerOptions,
+                               List<String> supportedLanguageCodes) {
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/bisq_easy/OfferListItemDto.java b/http-api/src/main/java/bisq/dto/offer/bisq_easy/OfferListItemDto.java
new file mode 100644
index 0000000000..63598edf13
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/bisq_easy/OfferListItemDto.java
@@ -0,0 +1,73 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.bisq_easy;
+
+import bisq.dto.user.reputation.ReputationScoreDto;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.util.List;
+
+@Getter
+@ToString
+@EqualsAndHashCode
+public class OfferListItemDto {
+    private final BisqEasyOfferDto bisqEasyOffer;
+    @JsonProperty("isMyOffer")
+    private final boolean isMyOffer;
+    private final String nym;
+    private final String userName;
+    private final ReputationScoreDto reputationScore;
+    private final String formattedDate;
+    private final String formattedQuoteAmount;
+    private final String formattedBaseAmount;
+    private final String formattedPrice;
+    private final String formattedPriceSpec;
+    private final List<String> quoteSidePaymentMethods;
+    private final List<String> baseSidePaymentMethods;
+
+    @JsonCreator
+    public OfferListItemDto(BisqEasyOfferDto bisqEasyOffer,
+                            boolean isMyOffer,
+                            String nym,
+                            String userName,
+                            ReputationScoreDto reputationScore,
+                            String formattedDate,
+                            String formattedQuoteAmount,
+                            String formattedBaseAmount,
+                            String formattedPrice,
+                            String formattedPriceSpec,
+                            List<String> quoteSidePaymentMethods,
+                            List<String> baseSidePaymentMethods) {
+        this.bisqEasyOffer = bisqEasyOffer;
+        this.isMyOffer = isMyOffer;
+        this.nym = nym;
+        this.userName = userName;
+        this.reputationScore = reputationScore;
+        this.formattedDate = formattedDate;
+        this.formattedQuoteAmount = formattedQuoteAmount;
+        this.formattedBaseAmount = formattedBaseAmount;
+        this.formattedPrice = formattedPrice;
+        this.formattedPriceSpec = formattedPriceSpec;
+        this.quoteSidePaymentMethods = quoteSidePaymentMethods;
+        this.baseSidePaymentMethods = baseSidePaymentMethods;
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/options/OfferOptionDto.java b/http-api/src/main/java/bisq/dto/offer/options/OfferOptionDto.java
new file mode 100644
index 0000000000..677446eace
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/options/OfferOptionDto.java
@@ -0,0 +1,40 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.options;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+
+@JsonTypeInfo(
+        use = JsonTypeInfo.Id.NAME,
+        include = JsonTypeInfo.As.PROPERTY,
+        property = "type"
+)
+@JsonSubTypes({
+        @JsonSubTypes.Type(value = ReputationOptionDto.class, name = "ReputationOption"),
+        @JsonSubTypes.Type(value = TradeTermsOptionDto.class, name = "TradeTermsOption"),
+})
+@Getter
+@EqualsAndHashCode
+public abstract class OfferOptionDto {
+    protected OfferOptionDto() {
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/options/ReputationOptionDto.java b/http-api/src/main/java/bisq/dto/offer/options/ReputationOptionDto.java
new file mode 100644
index 0000000000..55ca3efdb8
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/options/ReputationOptionDto.java
@@ -0,0 +1,37 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.options;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@ToString
+@EqualsAndHashCode(callSuper = true)
+public final class ReputationOptionDto extends OfferOptionDto {
+    @Deprecated(since = "2.1.1")
+    private final long requiredTotalReputationScore;
+
+    @JsonCreator
+    public ReputationOptionDto(@JsonProperty("requiredTotalReputationScore") long requiredTotalReputationScore) {
+        this.requiredTotalReputationScore = requiredTotalReputationScore;
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/options/TradeTermsOptionDto.java b/http-api/src/main/java/bisq/dto/offer/options/TradeTermsOptionDto.java
new file mode 100644
index 0000000000..c6301e9f48
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/options/TradeTermsOptionDto.java
@@ -0,0 +1,36 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.options;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@ToString
+@EqualsAndHashCode(callSuper = true)
+public final class TradeTermsOptionDto extends OfferOptionDto {
+    private final String makersTradeTerms;
+
+    @JsonCreator
+    public TradeTermsOptionDto(@JsonProperty("makersTradeTerms") String makersTradeTerms) {
+        this.makersTradeTerms = makersTradeTerms;
+    }
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/offer/payment_method/BitcoinPaymentMethodSpecDto.java b/http-api/src/main/java/bisq/dto/offer/payment_method/BitcoinPaymentMethodSpecDto.java
new file mode 100644
index 0000000000..0660e92d0e
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/payment_method/BitcoinPaymentMethodSpecDto.java
@@ -0,0 +1,39 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.payment_method;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.util.Optional;
+
+@Getter
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public final class BitcoinPaymentMethodSpecDto extends PaymentMethodSpecDto {
+
+    @JsonCreator
+    public BitcoinPaymentMethodSpecDto(@JsonProperty("paymentMethod") String paymentMethod, @JsonProperty("saltedMakerAccountId") Optional<String> saltedMakerAccountId) {
+        super(paymentMethod, saltedMakerAccountId);
+    }
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/offer/payment_method/FiatPaymentMethodSpecDto.java b/http-api/src/main/java/bisq/dto/offer/payment_method/FiatPaymentMethodSpecDto.java
new file mode 100644
index 0000000000..2ce096fcd0
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/payment_method/FiatPaymentMethodSpecDto.java
@@ -0,0 +1,38 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.payment_method;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.util.Optional;
+
+@Getter
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public final class FiatPaymentMethodSpecDto extends PaymentMethodSpecDto {
+    @JsonCreator
+    public FiatPaymentMethodSpecDto(@JsonProperty("paymentMethod") String paymentMethod, @JsonProperty("saltedMakerAccountId") Optional<String> saltedMakerAccountId) {
+        super(paymentMethod, saltedMakerAccountId);
+    }
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/offer/payment_method/PaymentMethodSpecDto.java b/http-api/src/main/java/bisq/dto/offer/payment_method/PaymentMethodSpecDto.java
new file mode 100644
index 0000000000..15fc3c358c
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/payment_method/PaymentMethodSpecDto.java
@@ -0,0 +1,55 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.payment_method;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.util.Optional;
+
+@ToString
+@Getter
+@EqualsAndHashCode
+
+@JsonTypeInfo(
+        use = JsonTypeInfo.Id.NAME, 
+        include = JsonTypeInfo.As.PROPERTY, 
+        property = "type"
+)
+@JsonSubTypes({
+        @JsonSubTypes.Type(value = FiatPaymentMethodSpecDto.class, name = "FiatPaymentMethodSpec"),
+        @JsonSubTypes.Type(value = BitcoinPaymentMethodSpecDto.class, name = "BitcoinPaymentMethodSpec"),
+})
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public abstract class PaymentMethodSpecDto {
+    protected final Optional<String> saltedMakerAccountId;
+    protected final String paymentMethod;
+
+    protected PaymentMethodSpecDto(String paymentMethod) {
+        this(paymentMethod, Optional.empty());
+    }
+
+    protected PaymentMethodSpecDto(String paymentMethod, Optional<String> saltedMakerAccountId) {
+        this.paymentMethod = paymentMethod;
+        this.saltedMakerAccountId = saltedMakerAccountId;
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/price/spec/FixPriceSpecDto.java b/http-api/src/main/java/bisq/dto/offer/price/spec/FixPriceSpecDto.java
new file mode 100644
index 0000000000..5e5e68f480
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/price/spec/FixPriceSpecDto.java
@@ -0,0 +1,37 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.price.spec;
+
+import bisq.dto.common.monetary.PriceQuoteDto;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class FixPriceSpecDto extends PriceSpecDto {
+    private final PriceQuoteDto priceQuote;
+
+    @JsonCreator
+    public FixPriceSpecDto(@JsonProperty("priceQuote") PriceQuoteDto priceQuote) {
+        this.priceQuote = priceQuote;
+    }
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/offer/price/spec/FloatPriceSpecDto.java b/http-api/src/main/java/bisq/dto/offer/price/spec/FloatPriceSpecDto.java
new file mode 100644
index 0000000000..a0ee7da649
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/price/spec/FloatPriceSpecDto.java
@@ -0,0 +1,36 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.price.spec;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class FloatPriceSpecDto extends PriceSpecDto {
+    private final double percentage;
+
+    @JsonCreator
+    public FloatPriceSpecDto(@JsonProperty("percentage") double percentage) {
+        this.percentage = percentage;
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/price/spec/MarketPriceSpecDto.java b/http-api/src/main/java/bisq/dto/offer/price/spec/MarketPriceSpecDto.java
new file mode 100644
index 0000000000..382ff00a06
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/price/spec/MarketPriceSpecDto.java
@@ -0,0 +1,31 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.price.spec;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@EqualsAndHashCode(callSuper = true)
+//@JsonIgnoreProperties(ignoreUnknown = true)
+public class MarketPriceSpecDto extends PriceSpecDto {
+    public MarketPriceSpecDto() {
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/offer/price/spec/PriceSpecDto.java b/http-api/src/main/java/bisq/dto/offer/price/spec/PriceSpecDto.java
new file mode 100644
index 0000000000..3916d377c2
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/offer/price/spec/PriceSpecDto.java
@@ -0,0 +1,41 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.offer.price.spec;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+@EqualsAndHashCode
+@Getter
+@JsonTypeInfo(
+        use = JsonTypeInfo.Id.NAME, 
+        include = JsonTypeInfo.As.PROPERTY, 
+        property = "type"
+)
+@JsonSubTypes({
+        @JsonSubTypes.Type(value = FixPriceSpecDto.class, name = "FixPriceSpec"),
+        @JsonSubTypes.Type(value = FloatPriceSpecDto.class, name = "FloatPriceSpec"),
+        @JsonSubTypes.Type(value = MarketPriceSpecDto.class, name = "MarketPriceSpec")
+})
+
+public abstract class PriceSpecDto {
+    protected PriceSpecDto() {
+    }
+}
diff --git a/http-api/src/main/java/bisq/dto/security/keys/KeyPairDto.java b/http-api/src/main/java/bisq/dto/security/keys/KeyPairDto.java
new file mode 100644
index 0000000000..44bc46e392
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/security/keys/KeyPairDto.java
@@ -0,0 +1,21 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.security.keys;
+
+public record KeyPairDto(PublicKeyDto publicKey, PrivateKeyDto privateKey) {
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/security/keys/PrivateKeyDto.java b/http-api/src/main/java/bisq/dto/security/keys/PrivateKeyDto.java
new file mode 100644
index 0000000000..57fb23e1a2
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/security/keys/PrivateKeyDto.java
@@ -0,0 +1,22 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.security.keys;
+
+
+public record PrivateKeyDto(String encoded) {
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/security/keys/PubKeyDto.java b/http-api/src/main/java/bisq/dto/security/keys/PubKeyDto.java
new file mode 100644
index 0000000000..befd24201b
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/security/keys/PubKeyDto.java
@@ -0,0 +1,21 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.security.keys;
+
+public record PubKeyDto(PublicKeyDto publicKey, String keyId, String hash, String id) {
+}
diff --git a/http-api/src/main/java/bisq/dto/security/keys/PublicKeyDto.java b/http-api/src/main/java/bisq/dto/security/keys/PublicKeyDto.java
new file mode 100644
index 0000000000..da0354e285
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/security/keys/PublicKeyDto.java
@@ -0,0 +1,22 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.security.keys;
+
+
+public record PublicKeyDto(String encoded) {
+}
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/dto/security/pow/ProofOfWorkDto.java b/http-api/src/main/java/bisq/dto/security/pow/ProofOfWorkDto.java
new file mode 100644
index 0000000000..6d661320c5
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/security/pow/ProofOfWorkDto.java
@@ -0,0 +1,29 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.security.pow;
+
+import javax.annotation.Nullable;
+
+public record ProofOfWorkDto(
+        String payload,
+        long counter,
+        @Nullable String challenge,
+        double difficulty,
+        String solution,
+        long duration) {
+}
diff --git a/http-api/src/main/java/bisq/dto/user/profile/UserProfileDto.java b/http-api/src/main/java/bisq/dto/user/profile/UserProfileDto.java
new file mode 100644
index 0000000000..51df686dca
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/user/profile/UserProfileDto.java
@@ -0,0 +1,34 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.user.profile;
+
+import bisq.dto.network.identity.NetworkIdDto;
+import bisq.dto.security.pow.ProofOfWorkDto;
+
+public record UserProfileDto(int version,
+                             String nickName,
+                             ProofOfWorkDto proofOfWork,
+                             int avatarVersion,
+                             NetworkIdDto networkId,
+                             String terms,
+                             String statement,
+                             String applicationVersion,
+                             String nym,
+                             String userName,
+                             long publishDate) {
+}
diff --git a/http-api/src/main/java/bisq/dto/user/reputation/ReputationScoreDto.java b/http-api/src/main/java/bisq/dto/user/reputation/ReputationScoreDto.java
new file mode 100644
index 0000000000..cf6dcce0a2
--- /dev/null
+++ b/http-api/src/main/java/bisq/dto/user/reputation/ReputationScoreDto.java
@@ -0,0 +1,21 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.dto.user.reputation;
+
+public record ReputationScoreDto(long totalScore, double fiveSystemScore, int ranking) {
+}
diff --git a/http-api/src/main/java/bisq/http_api/HttpApiService.java b/http-api/src/main/java/bisq/http_api/HttpApiService.java
index 127d695751..682ca6b07f 100644
--- a/http-api/src/main/java/bisq/http_api/HttpApiService.java
+++ b/http-api/src/main/java/bisq/http_api/HttpApiService.java
@@ -18,19 +18,23 @@
 package bisq.http_api;
 
 import bisq.bonded_roles.BondedRolesService;
-import bisq.http_api.rest_api.domain.market_price.MarketPriceRestApi;
 import bisq.chat.ChatService;
-import bisq.http_api.rest_api.domain.offerbook.OfferbookRestApi;
 import bisq.common.application.Service;
 import bisq.common.util.CompletableFutureUtils;
 import bisq.http_api.rest_api.RestApiResourceConfig;
 import bisq.http_api.rest_api.RestApiService;
+import bisq.http_api.rest_api.domain.market_price.MarketPriceRestApi;
+import bisq.http_api.rest_api.domain.offer.OfferRestApi;
+import bisq.http_api.rest_api.domain.offerbook.OfferbookRestApi;
+import bisq.http_api.rest_api.domain.trade.TradeRestApi;
+import bisq.http_api.rest_api.domain.user_identity.UserIdentityRestApi;
 import bisq.http_api.web_socket.WebSocketRestApiResourceConfig;
 import bisq.http_api.web_socket.WebSocketService;
 import bisq.network.NetworkService;
 import bisq.security.SecurityService;
+import bisq.support.SupportService;
+import bisq.trade.TradeService;
 import bisq.user.UserService;
-import bisq.http_api.rest_api.domain.user_identity.UserIdentityRestApi;
 import lombok.extern.slf4j.Slf4j;
 
 import java.util.Optional;
@@ -51,18 +55,35 @@ public HttpApiService(RestApiService.Config restApiConfig,
                           NetworkService networkService,
                           UserService userService,
                           BondedRolesService bondedRolesService,
-                          ChatService chatService) {
+                          ChatService chatService,
+                          SupportService supportedService,
+                          TradeService tradeService) {
         boolean restApiConfigEnabled = restApiConfig.isEnabled();
         boolean webSocketConfigEnabled = webSocketConfig.isEnabled();
         if (restApiConfigEnabled || webSocketConfigEnabled) {
             OfferbookRestApi offerbookRestApi = new OfferbookRestApi(chatService.getBisqEasyOfferbookChannelService(),
                     bondedRolesService.getMarketPriceService(),
                     userService);
+            OfferRestApi offerRestApi = new OfferRestApi(chatService,
+                    bondedRolesService.getMarketPriceService(),
+                    userService,
+                    supportedService,
+                    tradeService);
+            TradeRestApi tradeRestApi = new TradeRestApi(chatService,
+                    bondedRolesService.getMarketPriceService(),
+                    userService,
+                    supportedService,
+                    tradeService);
             UserIdentityRestApi userIdentityRestApi = new UserIdentityRestApi(securityService, userService.getUserIdentityService());
             MarketPriceRestApi marketPriceRestApi = new MarketPriceRestApi(bondedRolesService.getMarketPriceService());
 
             if (restApiConfigEnabled) {
-                var restApiResourceConfig = new RestApiResourceConfig(restApiConfig.getRestApiBaseUrl(), offerbookRestApi, userIdentityRestApi, marketPriceRestApi);
+                var restApiResourceConfig = new RestApiResourceConfig(restApiConfig.getRestApiBaseUrl(),
+                        offerbookRestApi,
+                        offerRestApi,
+                        tradeRestApi,
+                        userIdentityRestApi,
+                        marketPriceRestApi);
                 this.restApiService = Optional.of(new RestApiService(restApiConfig, restApiResourceConfig));
             } else {
                 this.restApiService = Optional.empty();
@@ -71,6 +92,8 @@ public HttpApiService(RestApiService.Config restApiConfig,
             if (webSocketConfigEnabled) {
                 var webSocketResourceConfig = new WebSocketRestApiResourceConfig(webSocketConfig.getRestApiBaseUrl(),
                         offerbookRestApi,
+                        offerRestApi,
+                        tradeRestApi,
                         userIdentityRestApi,
                         marketPriceRestApi);
                 this.webSocketService = Optional.of(new WebSocketService(webSocketConfig,
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/RestApiResourceConfig.java b/http-api/src/main/java/bisq/http_api/rest_api/RestApiResourceConfig.java
index 5966cbb814..24c81f3d57 100644
--- a/http-api/src/main/java/bisq/http_api/rest_api/RestApiResourceConfig.java
+++ b/http-api/src/main/java/bisq/http_api/rest_api/RestApiResourceConfig.java
@@ -1,7 +1,9 @@
 package bisq.http_api.rest_api;
 
 import bisq.http_api.rest_api.domain.market_price.MarketPriceRestApi;
+import bisq.http_api.rest_api.domain.offer.OfferRestApi;
 import bisq.http_api.rest_api.domain.offerbook.OfferbookRestApi;
+import bisq.http_api.rest_api.domain.trade.TradeRestApi;
 import bisq.http_api.rest_api.domain.user_identity.UserIdentityRestApi;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
@@ -12,6 +14,8 @@
 public class RestApiResourceConfig extends BaseRestApiResourceConfig {
     public RestApiResourceConfig(String swaggerBaseUrl,
                                  OfferbookRestApi offerbookRestApi,
+                                 OfferRestApi offerRestApi,
+                                 TradeRestApi tradeRestApi,
                                  UserIdentityRestApi userIdentityRestApi ,
                                  MarketPriceRestApi marketPriceRestApi) {
         super(swaggerBaseUrl);
@@ -22,6 +26,8 @@ public RestApiResourceConfig(String swaggerBaseUrl,
         // As we want to pass the dependencies in the constructor, so we need the hack
         // with AbstractBinder to register resources as classes for Swagger
         register(OfferbookRestApi.class);
+        register(OfferRestApi.class);
+        register(TradeRestApi.class);
         register(UserIdentityRestApi.class);
         register(MarketPriceRestApi.class);
 
@@ -29,6 +35,8 @@ public RestApiResourceConfig(String swaggerBaseUrl,
             @Override
             protected void configure() {
                 bind(offerbookRestApi).to(OfferbookRestApi.class);
+                bind(offerRestApi).to(OfferRestApi.class);
+                bind(tradeRestApi).to(TradeRestApi.class);
                 bind(userIdentityRestApi).to(UserIdentityRestApi.class);
                 bind(marketPriceRestApi).to(MarketPriceRestApi.class);
             }
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/MarketPriceRestApi.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/MarketPriceRestApi.java
index 4635c58176..c0358680a8 100644
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/MarketPriceRestApi.java
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/MarketPriceRestApi.java
@@ -20,6 +20,8 @@
 import bisq.bonded_roles.market_price.MarketPrice;
 import bisq.bonded_roles.market_price.MarketPriceService;
 import bisq.common.currency.Market;
+import bisq.dto.DtoMappings;
+import bisq.dto.common.monetary.PriceQuoteDto;
 import bisq.http_api.rest_api.domain.RestApiBase;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
@@ -58,7 +60,7 @@ public MarketPriceRestApi(MarketPriceService marketPriceService) {
                     @ApiResponse(
                             responseCode = "200",
                             description = "Market price quotes retrieved successfully",
-                            content = @Content(schema = @Schema(implementation = MarketPriceResponse.class))
+                            content = @Content(schema = @Schema(implementation = QuotesResponse.class))
                     ),
                     @ApiResponse(responseCode = "404", description = "Market price quotes not found"),
                     @ApiResponse(responseCode = "500", description = "Internal server error")
@@ -67,19 +69,19 @@ public MarketPriceRestApi(MarketPriceService marketPriceService) {
     public Response getQuotes() {
         try {
             Map<Market, MarketPrice> marketPriceByCurrencyMap = marketPriceService.getMarketPriceByCurrencyMap();
-            Map<String, Long> result = marketPriceService.getMarketPriceByCurrencyMap()
+            Map<String, PriceQuoteDto> result = marketPriceService.getMarketPriceByCurrencyMap()
                     .entrySet().stream()
                     .filter(entry->entry.getKey().getBaseCurrencyCode().equals("BTC")) // We get altcoin quotes as well
                     .collect(Collectors.toMap(
                             entry -> entry.getKey().getQuoteCurrencyCode(),
-                            entry -> entry.getValue().getPriceQuote().getValue()
+                            entry -> DtoMappings.PriceQuoteMapping.from(entry.getValue().getPriceQuote())
                     ));
 
             if (result.isEmpty()) {
                 return buildNotFoundResponse("No market price quotes found.");
             }
 
-            return buildOkResponse(new MarketPriceResponse(result));
+            return buildOkResponse(new QuotesResponse(result));
         } catch (Exception ex) {
             log.error("Failed to retrieve market price quotes", ex);
             return buildErrorResponse("An error occurred while retrieving market prices.");
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/MarketPriceResponse.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/QuotesResponse.java
similarity index 75%
rename from http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/MarketPriceResponse.java
rename to http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/QuotesResponse.java
index c500bdf00f..a192a4bebf 100644
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/MarketPriceResponse.java
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/market_price/QuotesResponse.java
@@ -17,20 +17,14 @@
 
 package bisq.http_api.rest_api.domain.market_price;
 
+import bisq.dto.common.monetary.PriceQuoteDto;
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
 
 import java.util.Map;
 
 /**
  * Response DTO for market price quotes.
  */
-@Getter
-public class MarketPriceResponse {
-    @Schema(description = "Map of currency codes to market price quotes")
-    private final Map<String, Long> quotes;
-
-    public MarketPriceResponse(Map<String, Long> quotes) {
-        this.quotes = quotes;
-    }
+public record QuotesResponse(
+        @Schema(description = "Map of currency codes to market price quotes") Map<String, PriceQuoteDto> quotes) {
 }
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/CreateOfferRequest.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/CreateOfferRequest.java
new file mode 100644
index 0000000000..5adf13f115
--- /dev/null
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/CreateOfferRequest.java
@@ -0,0 +1,34 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.http_api.rest_api.domain.offer;
+
+import bisq.dto.common.currency.MarketDto;
+import bisq.dto.offer.DirectionDto;
+import bisq.dto.offer.amount.spec.AmountSpecDto;
+import bisq.dto.offer.price.spec.PriceSpecDto;
+
+import java.util.Set;
+
+public record CreateOfferRequest(DirectionDto direction,
+                                 MarketDto market,
+                                 Set<String> bitcoinPaymentMethods,
+                                 Set<String> fiatPaymentMethods,
+                                 AmountSpecDto amountSpec,
+                                 PriceSpecDto priceSpec,
+                                 Set<String> supportedLanguageCodes) {
+}
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/CreateOfferResponse.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/CreateOfferResponse.java
new file mode 100644
index 0000000000..fac78179f6
--- /dev/null
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/CreateOfferResponse.java
@@ -0,0 +1,21 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.http_api.rest_api.domain.offer;
+
+public record CreateOfferResponse(String offerId) {
+}
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/OfferRestApi.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/OfferRestApi.java
new file mode 100644
index 0000000000..b0bccda22d
--- /dev/null
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/offer/OfferRestApi.java
@@ -0,0 +1,170 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.http_api.rest_api.domain.offer;
+
+import bisq.account.payment_method.BitcoinPaymentMethod;
+import bisq.account.payment_method.BitcoinPaymentMethodUtil;
+import bisq.account.payment_method.FiatPaymentMethod;
+import bisq.account.payment_method.FiatPaymentMethodUtil;
+import bisq.bisq_easy.BisqEasyServiceUtil;
+import bisq.bonded_roles.market_price.MarketPriceService;
+import bisq.chat.ChatService;
+import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannelService;
+import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookMessage;
+import bisq.chat.bisqeasy.open_trades.BisqEasyOpenTradeChannelService;
+import bisq.common.currency.Market;
+import bisq.dto.DtoMappings;
+import bisq.http_api.rest_api.domain.RestApiBase;
+import bisq.offer.Direction;
+import bisq.offer.amount.spec.AmountSpec;
+import bisq.offer.bisq_easy.BisqEasyOffer;
+import bisq.offer.price.spec.PriceSpec;
+import bisq.support.SupportService;
+import bisq.support.mediation.MediationRequestService;
+import bisq.trade.TradeService;
+import bisq.trade.bisq_easy.BisqEasyTradeService;
+import bisq.user.UserService;
+import bisq.user.banned.BannedUserService;
+import bisq.user.identity.UserIdentity;
+import bisq.user.identity.UserIdentityService;
+import bisq.user.profile.UserProfile;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.container.AsyncResponse;
+import jakarta.ws.rs.container.Suspended;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Path("/offers")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Tag(name = "Bisq Easy Offer API")
+public class OfferRestApi extends RestApiBase {
+    private final BisqEasyOfferbookChannelService bisqEasyOfferbookChannelService;
+    private final ChatService chatService;
+    private final MarketPriceService marketPriceService;
+    private final UserIdentityService userIdentityService;
+    private final BannedUserService bannedUserService;
+    private final MediationRequestService mediationRequestService;
+    private final BisqEasyTradeService bisqEasyTradeService;
+    private final BisqEasyOpenTradeChannelService bisqEasyOpenTradeChannelService;
+
+    public OfferRestApi(ChatService chatService,
+                        MarketPriceService marketPriceService,
+                        UserService userService,
+                        SupportService supportedService,
+                        TradeService tradeService) {
+        this.bisqEasyOfferbookChannelService = chatService.getBisqEasyOfferbookChannelService();
+        this.chatService = chatService;
+        this.marketPriceService = marketPriceService;
+        userIdentityService = userService.getUserIdentityService();
+        bannedUserService = userService.getBannedUserService();
+        mediationRequestService = supportedService.getMediationRequestService();
+        bisqEasyTradeService = tradeService.getBisqEasyTradeService();
+        bisqEasyOpenTradeChannelService = chatService.getBisqEasyOpenTradeChannelService();
+    }
+
+    @POST
+    @Operation(
+            summary = "Create and Publish Bisq Easy Offer",
+            description = "Creates a Bisq Easy Offer and publish it to the network.",
+            requestBody = @RequestBody(
+                    description = "",
+                    content = @Content(schema = @Schema(implementation = CreateOfferRequest.class))
+            ),
+            responses = {
+                    @ApiResponse(responseCode = "201", description = "",
+                            content = @Content(schema = @Schema(example = ""))),
+                    @ApiResponse(responseCode = "400", description = "Invalid input"),
+                    @ApiResponse(responseCode = "500", description = "Internal server error")
+            }
+    )
+    public void createOffer(CreateOfferRequest request, @Suspended AsyncResponse asyncResponse) {
+        asyncResponse.setTimeout(10, TimeUnit.SECONDS);
+        asyncResponse.setTimeoutHandler(response -> {
+            response.resume(buildResponse(Response.Status.SERVICE_UNAVAILABLE, "Request timed out"));
+        });
+        try {
+            UserIdentity userIdentity = userIdentityService.getSelectedUserIdentity();
+            Direction direction = DtoMappings.DirectionMapping.toPojo(request.direction());
+            Market market = DtoMappings.MarketMapping.toPojo(request.market());
+            List<BitcoinPaymentMethod> bitcoinPaymentMethods = request.bitcoinPaymentMethods().stream()
+                    .map(BitcoinPaymentMethodUtil::getPaymentMethod)
+                    .collect(Collectors.toList());
+            List<FiatPaymentMethod> fiatPaymentMethods = request.fiatPaymentMethods().stream()
+                    .map(FiatPaymentMethodUtil::getPaymentMethod)
+                    .collect(Collectors.toList());
+            AmountSpec amountSpec = DtoMappings.AmountSpecMapping.toPojo(request.amountSpec());
+            PriceSpec priceSpec = DtoMappings.PriceSpecMapping.toPojo(request.priceSpec());
+            List<String> supportedLanguageCodes = new ArrayList<>(request.supportedLanguageCodes());
+            String chatMessageText = BisqEasyServiceUtil.createOfferBookMessageFromPeerPerspective(userIdentity.getNickName(),
+                    marketPriceService,
+                    direction,
+                    market,
+                    bitcoinPaymentMethods,
+                    fiatPaymentMethods,
+                    amountSpec,
+                    priceSpec);
+            UserProfile userProfile = userIdentity.getUserProfile();
+            BisqEasyOffer bisqEasyOffer = new BisqEasyOffer(
+                    userProfile.getNetworkId(),
+                    direction,
+                    market,
+                    amountSpec,
+                    priceSpec,
+                    bitcoinPaymentMethods,
+                    fiatPaymentMethods,
+                    userProfile.getTerms(),
+                    supportedLanguageCodes);
+            String channelId = bisqEasyOfferbookChannelService.findChannel(market).orElseThrow().getId();
+            BisqEasyOfferbookMessage myOfferMessage = new BisqEasyOfferbookMessage(channelId,
+                    userProfile.getId(),
+                    Optional.of(bisqEasyOffer),
+                    Optional.of(chatMessageText),
+                    Optional.empty(),
+                    new Date().getTime(),
+                    false);
+            bisqEasyOfferbookChannelService.publishChatMessage(myOfferMessage, userIdentity).get();
+            asyncResponse.resume(buildResponse(Response.Status.CREATED, new CreateOfferResponse(bisqEasyOffer.getId())));
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            asyncResponse.resume(buildErrorResponse("Thread was interrupted."));
+        } catch (IllegalArgumentException e) {
+            asyncResponse.resume(buildResponse(Response.Status.BAD_REQUEST, "Invalid input: " + e.getMessage()));
+        } catch (Exception e) {
+            asyncResponse.resume(buildErrorResponse("An unexpected error occurred."));
+        }
+    }
+}
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/OfferListItemDto.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/OfferListItemDto.java
deleted file mode 100644
index 500befd577..0000000000
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/OfferListItemDto.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * This file is part of Bisq.
- *
- * Bisq is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Bisq is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package bisq.http_api.rest_api.domain.offerbook;
-
-import bisq.offer.Direction;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.ToString;
-
-import java.util.List;
-
-@Getter
-@ToString
-@Schema(name = "OfferListItem", description = "Detailed information about an offer in the offerbook.")
-public class OfferListItemDto {
-    @Schema(description = "Unique identifier for the message.", example = "msg-123456")
-    private final String messageId;
-    @Schema(description = "Unique identifier for the offer.", example = "offer-987654")
-    private final String offerId;
-    @JsonProperty("isMyMessage")
-    @Schema(description = "Indicates whether this message belongs to the current user.", example = "true")
-    private final boolean isMyMessage;
-    @Schema(description = "Direction of the offer (buy or sell).", implementation = Direction.class)
-    private final Direction direction;
-    @Schema(description = "Quote currency code of the offer.", example = "USD")
-    private final String quoteCurrencyCode;
-    @Schema(description = "Title of the offer.", example = "Buy 1 BTC at $30,000")
-    private final String offerTitle;
-    @Schema(description = "Timestamp of the offer in milliseconds since epoch.", example = "1672531200000")
-    private final long date;
-    @Schema(description = "Formatted date string for the offer.", example = "2023-01-01 12:00:00")
-    private final String formattedDate;
-    @Schema(description = "Anonymous pseudonym of the user.", example = "Nym123")
-    private final String nym;
-    @Schema(description = "Username of the offer's creator.", example = "Alice")
-    private final String userName;
-    @Schema(description = "Reputation score of the user who created the offer.", implementation = ReputationScoreDto.class)
-    private final ReputationScoreDto reputationScore;
-    @Schema(description = "Formatted amount for the quoted currency.", example = "30,000 USD")
-    private final String formattedQuoteAmount;
-    @Schema(description = "Formatted price of the offer.", example = "$30,000 per BTC")
-    private final String formattedPrice;
-    @Schema(description = "List of payment methods supported by the quote side.", example = "[\"Bank Transfer\", \"PayPal\"]")
-    private final List<String> quoteSidePaymentMethods;
-    @Schema(description = "List of payment methods supported by the base side.", example = "[\"Cash Deposit\"]")
-    private final List<String> baseSidePaymentMethods;
-    @Schema(description = "Supported language codes for the offer.", example = "en,es,fr")
-    private final String supportedLanguageCodes;
-
-    public OfferListItemDto(String messageId,
-                            String offerId,
-                            boolean isMyMessage,
-                            Direction direction,
-                            String quoteCurrencyCode,
-                            String offerTitle,
-                            long date,
-                            String formattedDate,
-                            String nym,
-                            String userName,
-                            ReputationScoreDto reputationScore,
-                            String formattedQuoteAmount,
-                            String formattedPrice,
-                            List<String> quoteSidePaymentMethods,
-                            List<String> baseSidePaymentMethods,
-                            String supportedLanguageCodes) {
-        this.messageId = messageId;
-        this.offerId = offerId;
-        this.isMyMessage = isMyMessage;
-        this.direction = direction;
-        this.quoteCurrencyCode = quoteCurrencyCode;
-        this.offerTitle = offerTitle;
-        this.date = date;
-        this.formattedDate = formattedDate;
-        this.nym = nym;
-        this.userName = userName;
-        this.reputationScore = reputationScore;
-        this.formattedQuoteAmount = formattedQuoteAmount;
-        this.formattedPrice = formattedPrice;
-        this.quoteSidePaymentMethods = quoteSidePaymentMethods;
-        this.baseSidePaymentMethods = baseSidePaymentMethods;
-        this.supportedLanguageCodes = supportedLanguageCodes;
-    }
-}
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/OfferbookRestApi.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/OfferbookRestApi.java
index 8177f67229..2ecc65a076 100644
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/OfferbookRestApi.java
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/OfferbookRestApi.java
@@ -17,31 +17,19 @@
 
 package bisq.http_api.rest_api.domain.offerbook;
 
-import bisq.account.payment_method.PaymentMethod;
 import bisq.bonded_roles.market_price.MarketPriceService;
 import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannel;
 import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannelService;
 import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookMessage;
 import bisq.common.currency.Market;
 import bisq.common.currency.MarketRepository;
+import bisq.dto.OfferListItemDtoFactory;
+import bisq.dto.offer.bisq_easy.OfferListItemDto;
 import bisq.http_api.rest_api.domain.RestApiBase;
-import bisq.common.util.StringUtils;
-import bisq.i18n.Res;
-import bisq.offer.Direction;
-import bisq.offer.amount.OfferAmountFormatter;
-import bisq.offer.amount.spec.AmountSpec;
-import bisq.offer.amount.spec.RangeAmountSpec;
-import bisq.offer.bisq_easy.BisqEasyOffer;
-import bisq.offer.payment_method.PaymentMethodSpecUtil;
-import bisq.offer.price.spec.PriceSpec;
-import bisq.offer.price.spec.PriceSpecFormatter;
-import bisq.presentation.formatters.DateFormatter;
 import bisq.user.UserService;
 import bisq.user.identity.UserIdentityService;
-import bisq.user.profile.UserProfile;
 import bisq.user.profile.UserProfileService;
 import bisq.user.reputation.ReputationService;
-import com.google.common.base.Joiner;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -52,8 +40,6 @@
 import jakarta.ws.rs.core.Response;
 import lombok.extern.slf4j.Slf4j;
 
-import java.text.DateFormat;
-import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -187,81 +173,17 @@ private Optional<List<OfferListItemDto>> findOffer(String marketCodes) {
                         .map(channel -> channel.getChatMessages()
                                 .stream()
                                 .filter(BisqEasyOfferbookMessage::hasBisqEasyOffer)
-                                .map(message -> {
-                                    BisqEasyOffer bisqEasyOffer = message.getBisqEasyOffer().orElseThrow();
-                                    long date = message.getDate();
-                                    String formattedDate = DateFormatter.formatDateTime(new Date(date), DateFormat.MEDIUM, DateFormat.SHORT,
-                                            true, " " + Res.get("temporal.at") + " ");
-                                    String authorUserProfileId = message.getAuthorUserProfileId();
-                                    Optional<UserProfile> senderUserProfile = userProfileService.findUserProfile(authorUserProfileId);
-                                    String nym = senderUserProfile.map(UserProfile::getNym).orElse("");
-                                    String userName = senderUserProfile.map(UserProfile::getUserName).orElse("");
-
-                                    ReputationScoreDto reputationScore = senderUserProfile.flatMap(reputationService::findReputationScore)
-                                            .map(score -> new ReputationScoreDto(
-                                                    score.getTotalScore(),
-                                                    score.getFiveSystemScore(),
-                                                    score.getRanking()
-                                            ))
-                                            .orElse(new ReputationScoreDto(0, 0, 0));
-                                    AmountSpec amountSpec = bisqEasyOffer.getAmountSpec();
-                                    PriceSpec priceSpec = bisqEasyOffer.getPriceSpec();
-                                    boolean hasAmountRange = amountSpec instanceof RangeAmountSpec;
-                                    // Market   market= bisqEasyOffer.getMarket();
-                                    String formattedQuoteAmount = OfferAmountFormatter.formatQuoteAmount(
-                                            marketPriceService,
-                                            amountSpec,
-                                            priceSpec,
-                                            market,
-                                            hasAmountRange,
-                                            true
-                                    );
-                                    String formattedPrice = PriceSpecFormatter.getFormattedPriceSpec(priceSpec, true);
-
-                                    List<String> quoteSidePaymentMethods = PaymentMethodSpecUtil.getPaymentMethods(bisqEasyOffer.getQuoteSidePaymentMethodSpecs())
-                                            .stream()
-                                            .map(PaymentMethod::getName)
-                                            .collect(Collectors.toList());
-
-                                    List<String> baseSidePaymentMethods = PaymentMethodSpecUtil.getPaymentMethods(bisqEasyOffer.getBaseSidePaymentMethodSpecs())
-                                            .stream()
-                                            .map(PaymentMethod::getName)
-                                            .collect(Collectors.toList());
-
-                                    String supportedLanguageCodes = Joiner.on(",").join(bisqEasyOffer.getSupportedLanguageCodes());
-                                    boolean isMyMessage = message.isMyMessage(userIdentityService);
-                                    Direction direction = bisqEasyOffer.getDirection();
-                                    String offerTitle = getOfferTitle(message, direction, isMyMessage);
-                                    String messageId = message.getId();
-                                    String offerId = bisqEasyOffer.getId();
-                                    return new OfferListItemDto(messageId,
-                                            offerId,
-                                            isMyMessage,
-                                            direction,
-                                            market.getQuoteCurrencyCode(),
-                                            offerTitle,
-                                            date,
-                                            formattedDate,
-                                            nym,
-                                            userName,
-                                            reputationScore,
-                                            formattedQuoteAmount,
-                                            formattedPrice,
-                                            quoteSidePaymentMethods,
-                                            baseSidePaymentMethods,
-                                            supportedLanguageCodes);
-                                })
+                                .map(this::createOfferListItemDto)
                                 .collect(Collectors.toList())
                         )
                 );
     }
 
-    private String getOfferTitle(BisqEasyOfferbookMessage message, Direction direction, boolean isMyMessage) {
-        if (isMyMessage) {
-            String directionString = StringUtils.capitalize(Res.get("offer." + direction.name().toLowerCase()));
-            return Res.get("bisqEasy.tradeWizard.review.chatMessage.myMessageTitle", directionString);
-        } else {
-            return message.getText();
-        }
+    private OfferListItemDto createOfferListItemDto(BisqEasyOfferbookMessage bisqEasyOfferbookMessage) {
+        return OfferListItemDtoFactory.createOfferListItemDto(userProfileService,
+                userIdentityService,
+                reputationService,
+                marketPriceService,
+                bisqEasyOfferbookMessage);
     }
 }
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/ReputationScoreDto.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/ReputationScoreDto.java
deleted file mode 100644
index d1184d225e..0000000000
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/offerbook/ReputationScoreDto.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * This file is part of Bisq.
- *
- * Bisq is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Bisq is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package bisq.http_api.rest_api.domain.offerbook;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-
-@Getter
-@Schema(name = "ReputationScoreDto", description = "User reputation details including total score, 5-star rating, and ranking.")
-public class ReputationScoreDto {
-    @Schema(description = "Total reputation score of the user.", example = "1500")
-    private final long totalScore;
-    @Schema(description = "5-star system equivalent score (out of 5).", example = "4.8")
-    private final double fiveSystemScore;
-    @Schema(description = "User's ranking among peers.", example = "12")
-    private final int ranking;
-
-    public ReputationScoreDto(long totalScore, double fiveSystemScore, int ranking) {
-        this.totalScore = totalScore;
-        this.fiveSystemScore = fiveSystemScore;
-        this.ranking = ranking;
-    }
-}
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TakeOfferRequest.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TakeOfferRequest.java
new file mode 100644
index 0000000000..78a1b6e5ed
--- /dev/null
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TakeOfferRequest.java
@@ -0,0 +1,25 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.http_api.rest_api.domain.trade;
+
+public record TakeOfferRequest(String offerId,
+                               long baseSideAmount,
+                               long quoteSideAmount,
+                               String bitcoinPaymentMethod,
+                               String fiatPaymentMethod) {
+}
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TakeOfferResponse.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TakeOfferResponse.java
new file mode 100644
index 0000000000..071fc27c8a
--- /dev/null
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TakeOfferResponse.java
@@ -0,0 +1,21 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.http_api.rest_api.domain.trade;
+
+public record TakeOfferResponse(String tradeId) {
+}
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TradeRestApi.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TradeRestApi.java
new file mode 100644
index 0000000000..f7bdf9a746
--- /dev/null
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/trade/TradeRestApi.java
@@ -0,0 +1,199 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.http_api.rest_api.domain.trade;
+
+import bisq.account.payment_method.BitcoinPaymentMethod;
+import bisq.account.payment_method.FiatPaymentMethod;
+import bisq.bonded_roles.market_price.MarketPriceService;
+import bisq.chat.ChatChannelDomain;
+import bisq.chat.ChatChannelSelectionService;
+import bisq.chat.ChatService;
+import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannelService;
+import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookMessage;
+import bisq.chat.bisqeasy.open_trades.BisqEasyOpenTradeChannelService;
+import bisq.common.monetary.Monetary;
+import bisq.common.util.StringUtils;
+import bisq.contract.bisq_easy.BisqEasyContract;
+import bisq.http_api.rest_api.domain.RestApiBase;
+import bisq.http_api.rest_api.domain.offer.CreateOfferRequest;
+import bisq.i18n.Res;
+import bisq.offer.bisq_easy.BisqEasyOffer;
+import bisq.offer.payment_method.BitcoinPaymentMethodSpec;
+import bisq.offer.payment_method.FiatPaymentMethodSpec;
+import bisq.offer.payment_method.PaymentMethodSpecUtil;
+import bisq.offer.price.spec.PriceSpec;
+import bisq.support.SupportService;
+import bisq.support.mediation.MediationRequestService;
+import bisq.trade.TradeService;
+import bisq.trade.bisq_easy.BisqEasyTrade;
+import bisq.trade.bisq_easy.BisqEasyTradeService;
+import bisq.trade.bisq_easy.protocol.BisqEasyProtocol;
+import bisq.user.UserService;
+import bisq.user.banned.BannedUserService;
+import bisq.user.identity.UserIdentity;
+import bisq.user.identity.UserIdentityService;
+import bisq.user.profile.UserProfile;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.container.AsyncResponse;
+import jakarta.ws.rs.container.Suspended;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+@Slf4j
+@Path("/trades")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Tag(name = "Bisq Easy Trade API")
+public class TradeRestApi extends RestApiBase {
+    private final BisqEasyOfferbookChannelService bisqEasyOfferbookChannelService;
+    private final ChatService chatService;
+    private final MarketPriceService marketPriceService;
+    private final UserIdentityService userIdentityService;
+    private final BannedUserService bannedUserService;
+    private final MediationRequestService mediationRequestService;
+    private final BisqEasyTradeService bisqEasyTradeService;
+    private final BisqEasyOpenTradeChannelService bisqEasyOpenTradeChannelService;
+
+    public TradeRestApi(ChatService chatService,
+                        MarketPriceService marketPriceService,
+                        UserService userService,
+                        SupportService supportedService,
+                        TradeService tradeService) {
+        this.bisqEasyOfferbookChannelService = chatService.getBisqEasyOfferbookChannelService();
+        this.chatService = chatService;
+        this.marketPriceService = marketPriceService;
+        userIdentityService = userService.getUserIdentityService();
+        bannedUserService = userService.getBannedUserService();
+        mediationRequestService = supportedService.getMediationRequestService();
+        bisqEasyTradeService = tradeService.getBisqEasyTradeService();
+        bisqEasyOpenTradeChannelService = chatService.getBisqEasyOpenTradeChannelService();
+    }
+
+    @POST
+    @Operation(
+            summary = "Create a Trade by Taking a Bisq Easy Offer",
+            description = "Create a Trade by Taking a Bisq Easy Offer.",
+            requestBody = @RequestBody(
+                    description = "",
+                    content = @Content(schema = @Schema(implementation = CreateOfferRequest.class))
+            ),
+            responses = {
+                    @ApiResponse(responseCode = "201", description = "",
+                            content = @Content(schema = @Schema(example = ""))),
+                    @ApiResponse(responseCode = "400", description = "Invalid input"),
+                    @ApiResponse(responseCode = "500", description = "Internal server error")
+            }
+    )
+    public void takeOffer(TakeOfferRequest request, @Suspended AsyncResponse asyncResponse) {
+        asyncResponse.setTimeout(150, TimeUnit.SECONDS); // We have 120 seconds socket timeout, so we should never get triggered here, as the message will be sent as mailbox message
+        asyncResponse.setTimeoutHandler(response -> {
+            response.resume(buildResponse(Response.Status.SERVICE_UNAVAILABLE, "Request timed out"));
+        });
+
+        try {
+            UserIdentity takerIdentity = userIdentityService.getSelectedUserIdentity();
+            checkArgument(!bannedUserService.isUserProfileBanned(takerIdentity.getUserProfile()), "Taker profile is banned");
+            //noinspection OptionalGetWithoutIsPresent
+            BisqEasyOffer bisqEasyOffer = bisqEasyOfferbookChannelService.getChannels().stream().flatMap(c -> c.getChatMessages().stream())
+                    .filter(BisqEasyOfferbookMessage::hasBisqEasyOffer)
+                    .map(e -> e.getBisqEasyOffer().get())
+                    .filter(e -> e.getId().equals(request.offerId()))
+                    .findFirst()
+                    .orElseThrow();
+            checkArgument(!bannedUserService.isNetworkIdBanned(bisqEasyOffer.getMakerNetworkId()), "Maker profile is banned");
+            Monetary baseSideAmount = Monetary.from(request.baseSideAmount(), bisqEasyOffer.getMarket().getBaseCurrencyCode());
+            Monetary quoteSideAmount = Monetary.from(request.quoteSideAmount(), bisqEasyOffer.getMarket().getBaseCurrencyCode());
+            BitcoinPaymentMethod bitcoinPaymentMethod = PaymentMethodSpecUtil.getBitcoinPaymentMethod(request.bitcoinPaymentMethod());
+            BitcoinPaymentMethodSpec bitcoinPaymentMethodSpec = new BitcoinPaymentMethodSpec(bitcoinPaymentMethod);
+            FiatPaymentMethod fiatPaymentMethod = PaymentMethodSpecUtil.getFiatPaymentMethod(request.fiatPaymentMethod());
+            FiatPaymentMethodSpec fiatPaymentMethodSpec = new FiatPaymentMethodSpec(fiatPaymentMethod);
+            Optional<UserProfile> mediator = mediationRequestService.selectMediator(bisqEasyOffer.getMakersUserProfileId(), takerIdentity.getId());
+            PriceSpec makersPriceSpec = bisqEasyOffer.getPriceSpec();
+            long marketPrice = marketPriceService.findMarketPrice(bisqEasyOffer.getMarket())
+                    .map(e -> e.getPriceQuote().getValue())
+                    .orElseThrow();
+            BisqEasyProtocol bisqEasyProtocol = bisqEasyTradeService.createBisqEasyProtocol(takerIdentity.getIdentity(),
+                    bisqEasyOffer,
+                    baseSideAmount,
+                    quoteSideAmount,
+                    bitcoinPaymentMethodSpec,
+                    fiatPaymentMethodSpec,
+                    mediator,
+                    makersPriceSpec,
+                    marketPrice);
+            BisqEasyTrade bisqEasyTrade = bisqEasyProtocol.getModel();
+            log.info("Selected mediator for trade {}: {}", bisqEasyTrade.getShortId(), mediator.map(UserProfile::getUserName).orElse("N/A"));
+
+            bisqEasyTradeService.takeOffer(bisqEasyTrade);
+            BisqEasyContract contract = bisqEasyTrade.getContract();
+
+            String tradeId = bisqEasyTrade.getId();
+            bisqEasyOpenTradeChannelService.sendTakeOfferMessage(tradeId, bisqEasyOffer, contract.getMediator())
+                    .thenAccept(result ->
+                            {
+                                // In case the user has switched to another market we want to select that market in the offer book
+                                ChatChannelSelectionService chatChannelSelectionService =
+                                        chatService.getChatChannelSelectionService(ChatChannelDomain.BISQ_EASY_OFFERBOOK);
+                                bisqEasyOfferbookChannelService.findChannel(contract.getOffer().getMarket())
+                                        .ifPresent(chatChannelSelectionService::selectChannel);
+                                bisqEasyOpenTradeChannelService.findChannelByTradeId(tradeId)
+                                        .ifPresent(channel -> {
+                                            String taker = userIdentityService.getSelectedUserIdentity().getUserProfile().getUserName();
+                                            String maker = channel.getPeer().getUserName();
+                                            String encoded = Res.encode("bisqEasy.takeOffer.tradeLogMessage", taker, maker);
+                                            chatService.getBisqEasyOpenTradeChannelService().sendTradeLogMessage(encoded, channel);
+                                        });
+                            }
+                    )
+                    .get();
+
+            // After the take offer is completed we check if errors happened
+            String errorMessage = bisqEasyTrade.errorMessageObservable().get();
+            checkArgument(errorMessage == null, "An error occurred at taking the offer: " + errorMessage +
+                    ". ErrorStackTrace: " + StringUtils.truncate(bisqEasyTrade.getErrorStackTrace(), 500));
+
+            String peersErrorMessage = bisqEasyTrade.peersErrorMessageObservable().get();
+            checkArgument(peersErrorMessage == null, "An error occurred at the peers side at taking the offer: " + peersErrorMessage +
+                    ". ErrorStackTrace: " + StringUtils.truncate(bisqEasyTrade.getPeersErrorStackTrace(), 500));
+
+            asyncResponse.resume(buildResponse(Response.Status.CREATED, new TakeOfferResponse(bisqEasyTrade.getId())));
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            asyncResponse.resume(buildErrorResponse("Thread was interrupted."));
+        } catch (IllegalArgumentException e) {
+            asyncResponse.resume(buildResponse(Response.Status.BAD_REQUEST, "Invalid input: " + e.getMessage()));
+        } catch (Exception e) {
+            asyncResponse.resume(buildErrorResponse("An unexpected error occurred."));
+        }
+    }
+}
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/CreateUserIdentityRequest.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/CreateUserIdentityRequest.java
index 56c6187682..d0b5731920 100644
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/CreateUserIdentityRequest.java
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/CreateUserIdentityRequest.java
@@ -21,7 +21,7 @@
 import lombok.Data;
 
 @Data
-@Schema(description = "Request payload for creating a new user identity.")
+@Schema(description = "Request key material for creating a new user identity.")
 public class CreateUserIdentityRequest {
     @Schema(description = "Nickname for the user", example = "Satoshi", required = true)
     private String nickName;
@@ -32,6 +32,6 @@ public class CreateUserIdentityRequest {
     @Schema(description = "User statement", example = "I am Satoshi")
     private String statement = "";
 
-    @Schema(description = "Prepared data as JSON object", required = true)
-    private PreparedData preparedData;
+    @Schema(description = "Key material for creating an user identity", required = true)
+    private KeyMaterialResponse keyMaterialResponse;
 }
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/UserProfileResponse.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/CreateUserIdentityResponse.java
similarity index 89%
rename from http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/UserProfileResponse.java
rename to http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/CreateUserIdentityResponse.java
index b0da323a33..8a85cdaef0 100644
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/UserProfileResponse.java
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/CreateUserIdentityResponse.java
@@ -24,11 +24,11 @@
 
 @Getter
 @Schema(name = "UserProfileResponse", description = "Response payload containing the user profile ID.")
-public class UserProfileResponse {
+public class CreateUserIdentityResponse {
     private final String userProfileId;
 
     @JsonCreator
-    public UserProfileResponse(@JsonProperty("userProfileId") String userProfileId) {
+    public CreateUserIdentityResponse(@JsonProperty("userProfileId") String userProfileId) {
         this.userProfileId = userProfileId;
     }
 }
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/PreparedData.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/KeyMaterialResponse.java
similarity index 62%
rename from http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/PreparedData.java
rename to http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/KeyMaterialResponse.java
index 6369f44072..e715216cfc 100644
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/PreparedData.java
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/KeyMaterialResponse.java
@@ -17,33 +17,25 @@
 
 package bisq.http_api.rest_api.domain.user_identity;
 
-import bisq.security.keys.JsonSerialization;
-import bisq.security.pow.ProofOfWork;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import bisq.dto.security.keys.KeyPairDto;
+import bisq.dto.security.pow.ProofOfWorkDto;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 
-import java.security.KeyPair;
-
 @Getter
-@Schema(name = "PreparedData")
-public final class PreparedData {
-    @JsonSerialize(using = JsonSerialization.KeyPair.Serializer.class)
-    @JsonDeserialize(using = JsonSerialization.KeyPair.Deserializer.class)
+@Schema(name = "KeyMaterial")
+public final class KeyMaterialResponse {
     @Schema(description = "Key pair",
             example = "{ \"privateKey\": \"MIGNAgEAMBAGByqGSM49AgEGBSuBBAAKBHYwdAIBAQQgky6PNO163DColHrGmSNMgY93amwpAO8ZA8/Pb+Xl5magBwYFK4EEAAqhRANCAARyZim9kPgZixR2+ALUs72fO2zzSkeV89w4oQpkRUct5ob4yHRIIwwrggjoCGmNUWqX/pNA18R46vNYTp8NWuSu\", \"publicKey\": \"MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcmYpvZD4GYsUdvgC1LO9nzts80pHlfPcOKEKZEVHLeaG+Mh0SCMMK4II6AhpjVFql/6TQNfEeOrzWE6fDVrkrg==\" }")
-    private KeyPair keyPair;
+    private KeyPairDto keyPair;
     @Schema(description = "ID", example = "b0edc477ec967379867ae44b1e030fa4f8e68327")
     private String id;
     @Schema(description = "Nym", example = "Ravenously-Poignant-Coordinate-695")
     private String nym;
-    @Schema(description = "User statement",
-            example = "{ \"payload\": \"[-80, -19, -60, 119, -20, -106, 115, 121, -122, 122, -28, 75, 30, 3, 15, -92, -8, -26, -125, 39]\", \"counter\": 93211, \"difficulty\": 65536.0, \"solution\": [0, 0, 0, 0, 0, 1, 108, 27], \"duration\": 19 }")
-    private ProofOfWork proofOfWork;
+    private ProofOfWorkDto proofOfWork;
 
-    public static PreparedData from(KeyPair keyPair, String id, String nym, ProofOfWork proofOfWork) {
-        PreparedData dto = new PreparedData();
+    public static KeyMaterialResponse from(KeyPairDto keyPair, String id, String nym, ProofOfWorkDto proofOfWork) {
+        KeyMaterialResponse dto = new KeyMaterialResponse();
         dto.keyPair = keyPair;
         dto.id = id;
         dto.nym = nym;
diff --git a/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/UserIdentityRestApi.java b/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/UserIdentityRestApi.java
index 71dde9fb13..75e286175d 100644
--- a/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/UserIdentityRestApi.java
+++ b/http-api/src/main/java/bisq/http_api/rest_api/domain/user_identity/UserIdentityRestApi.java
@@ -18,6 +18,9 @@
 package bisq.http_api.rest_api.domain.user_identity;
 
 import bisq.common.encoding.Hex;
+import bisq.dto.DtoMappings;
+import bisq.dto.security.keys.KeyPairDto;
+import bisq.dto.security.pow.ProofOfWorkDto;
 import bisq.http_api.rest_api.domain.RestApiBase;
 import bisq.security.DigestUtil;
 import bisq.security.SecurityService;
@@ -33,6 +36,8 @@
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.ws.rs.*;
+import jakarta.ws.rs.container.AsyncResponse;
+import jakarta.ws.rs.container.Suspended;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
 import lombok.extern.slf4j.Slf4j;
@@ -41,6 +46,7 @@
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -60,31 +66,88 @@ public UserIdentityRestApi(SecurityService securityService, UserIdentityService
     }
 
     @GET
-    @Path("/prepared-data")
+    @Path("/key-material")
     @Operation(
             summary = "Generate Prepared Data",
             description = "Generates a key pair, public key hash, Nym, and proof of work for a new user identity.",
             responses = {
                     @ApiResponse(responseCode = "201", description = "Prepared data generated successfully",
-                            content = @Content(schema = @Schema(implementation = PreparedData.class))),
+                            content = @Content(schema = @Schema(implementation = KeyMaterialResponse.class))),
                     @ApiResponse(responseCode = "500", description = "Internal server error")
             }
     )
-    public Response createPreparedData() {
+    public void getKeyMaterial(@Suspended AsyncResponse asyncResponse) {
+        asyncResponse.setTimeout(5, TimeUnit.SECONDS);
+        asyncResponse.setTimeoutHandler(response -> {
+            response.resume(buildResponse(Response.Status.SERVICE_UNAVAILABLE, "Request timed out"));
+        });
         try {
             KeyPair keyPair = securityService.getKeyBundleService().generateKeyPair();
             byte[] pubKeyHash = DigestUtil.hash(keyPair.getPublic().getEncoded());
             String id = Hex.encode(pubKeyHash);
             ProofOfWork proofOfWork = userIdentityService.mintNymProofOfWork(pubKeyHash);
             String nym = NymIdGenerator.generate(pubKeyHash, proofOfWork.getSolution());
-            PreparedData preparedData = PreparedData.from(keyPair, id, nym, proofOfWork);
-            return buildResponse(Response.Status.CREATED, preparedData);
+            KeyPairDto keyPairDto = DtoMappings.KeyPairDtoMapping.from(keyPair);
+            ProofOfWorkDto proofOfWorkDto = DtoMappings.ProofOfWorkDtoMapping.from(proofOfWork);
+            KeyMaterialResponse keyMaterialResponse = KeyMaterialResponse.from(keyPairDto, id, nym, proofOfWorkDto);
+            asyncResponse.resume(buildResponse(Response.Status.CREATED, keyMaterialResponse));
         } catch (Exception e) {
             log.error("Error generating prepared data", e);
-            return buildErrorResponse("Could not generate prepared data.");
+            asyncResponse.resume(buildErrorResponse("Could not generate prepared data."));
         }
     }
 
+
+    @POST
+    @Operation(
+            summary = "Create User Identity and Publish User Profile",
+            description = "Creates a new user identity and publishes the associated user profile.",
+            requestBody = @RequestBody(
+                    description = "Request payload containing user nickname, terms, statement, and prepared data.",
+                    content = @Content(schema = @Schema(implementation = CreateUserIdentityRequest.class))
+            ),
+            responses = {
+                    @ApiResponse(responseCode = "201", description = "User identity created successfully",
+                            content = @Content(schema = @Schema(example = "{ \"userProfileId\": \"d22d7b62ef442b5df03378f134bc8f54a2171cba\" }"))),
+                    @ApiResponse(responseCode = "400", description = "Invalid input"),
+                    @ApiResponse(responseCode = "500", description = "Internal server error")
+            }
+    )
+    public void createUserIdentity(CreateUserIdentityRequest request,
+                                   @Suspended AsyncResponse asyncResponse) {
+        asyncResponse.setTimeout(10, TimeUnit.SECONDS);
+        asyncResponse.setTimeoutHandler(response -> {
+            response.resume(buildResponse(Response.Status.SERVICE_UNAVAILABLE, "Request timed out"));
+        });
+
+        try {
+            KeyMaterialResponse keyMaterialResponse = request.getKeyMaterialResponse();
+            KeyPairDto keyPairDto = keyMaterialResponse.getKeyPair();
+            KeyPair keyPair = DtoMappings.KeyPairDtoMapping.toPojo(keyPairDto);
+            byte[] pubKeyHash = DigestUtil.hash(keyPair.getPublic().getEncoded());
+            int avatarVersion = 0;
+            ProofOfWorkDto proofOfWorkDto = keyMaterialResponse.getProofOfWork();
+            ProofOfWork proofOfWork = DtoMappings.ProofOfWorkDtoMapping.toPojo(proofOfWorkDto);
+            UserIdentity userIdentity = userIdentityService.createAndPublishNewUserProfile(request.getNickName(),
+                    keyPair,
+                    pubKeyHash,
+                    proofOfWork,
+                    avatarVersion,
+                    request.getTerms(),
+                    request.getStatement()).get();
+
+            asyncResponse.resume(buildResponse(Response.Status.CREATED, new CreateUserIdentityResponse(userIdentity.getId())));
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            asyncResponse.resume(buildErrorResponse("Thread was interrupted."));
+        } catch (IllegalArgumentException e) {
+            asyncResponse.resume(buildResponse(Response.Status.BAD_REQUEST, "Invalid input: " + e.getMessage()));
+        } catch (Exception e) {
+            asyncResponse.resume(buildErrorResponse("An unexpected error occurred."));
+        }
+    }
+
+
     @GET
     @Path("/{id}")
     @Operation(
@@ -144,44 +207,4 @@ public Response getSelectedUserProfile() {
         UserProfile userProfile = selectedUserIdentity.getUserProfile();
         return buildOkResponse(userProfile);
     }
-
-    @POST
-    @Operation(
-            summary = "Create and Publish User Identity",
-            description = "Creates a new user identity and publishes the associated user profile.",
-            requestBody = @RequestBody(
-                    description = "Request payload containing user nickname, terms, statement, and prepared data.",
-                    content = @Content(schema = @Schema(implementation = CreateUserIdentityRequest.class))
-            ),
-            responses = {
-                    @ApiResponse(responseCode = "201", description = "User identity created successfully",
-                            content = @Content(schema = @Schema(example = "{ \"userProfileId\": \"d22d7b62ef442b5df03378f134bc8f54a2171cba\" }"))),
-                    @ApiResponse(responseCode = "400", description = "Invalid input"),
-                    @ApiResponse(responseCode = "500", description = "Internal server error")
-            }
-    )
-    public Response createUserIdentityAndPublishUserProfile(CreateUserIdentityRequest request) {
-        try {
-            PreparedData preparedData = request.getPreparedData();
-            KeyPair keyPair = preparedData.getKeyPair();
-            byte[] pubKeyHash = DigestUtil.hash(keyPair.getPublic().getEncoded());
-            int avatarVersion = 0;
-            UserIdentity userIdentity = userIdentityService.createAndPublishNewUserProfile(request.getNickName(),
-                    keyPair,
-                    pubKeyHash,
-                    preparedData.getProofOfWork(),
-                    avatarVersion,
-                    request.getTerms(),
-                    request.getStatement()).get();
-            return buildResponse(Response.Status.CREATED, new UserProfileResponse(userIdentity.getId()));
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            return buildErrorResponse("Thread was interrupted.");
-        } catch (IllegalArgumentException e) {
-            return buildResponse(Response.Status.BAD_REQUEST, "Invalid input: " + e.getMessage());
-        } catch (Exception e) {
-            log.error("Error creating user identity", e);
-            return buildErrorResponse("An unexpected error occurred.");
-        }
-    }
 }
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/WebSocketMessage.java b/http-api/src/main/java/bisq/http_api/web_socket/WebSocketMessage.java
new file mode 100644
index 0000000000..5fab38eeef
--- /dev/null
+++ b/http-api/src/main/java/bisq/http_api/web_socket/WebSocketMessage.java
@@ -0,0 +1,42 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package bisq.http_api.web_socket;
+
+import bisq.http_api.web_socket.rest_api_proxy.WebSocketRestApiRequest;
+import bisq.http_api.web_socket.rest_api_proxy.WebSocketRestApiResponse;
+import bisq.http_api.web_socket.subscription.SubscriptionRequest;
+import bisq.http_api.web_socket.subscription.SubscriptionResponse;
+import bisq.http_api.web_socket.subscription.WebSocketEvent;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
+@JsonTypeInfo(
+        use = JsonTypeInfo.Id.NAME,
+        include = JsonTypeInfo.As.PROPERTY,
+        property = "type"
+)
+@JsonSubTypes({
+        @JsonSubTypes.Type(value = WebSocketRestApiRequest.class, name = "WebSocketRestApiRequest"),
+        @JsonSubTypes.Type(value = WebSocketRestApiResponse.class, name = "WebSocketRestApiResponse"),
+        @JsonSubTypes.Type(value = SubscriptionRequest.class, name = "SubscriptionRequest"),
+        @JsonSubTypes.Type(value = SubscriptionResponse.class, name = "SubscriptionResponse"),
+        @JsonSubTypes.Type(value = WebSocketEvent.class, name = "WebSocketEvent")
+})
+public interface WebSocketMessage {
+}
+
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/WebSocketRestApiResourceConfig.java b/http-api/src/main/java/bisq/http_api/web_socket/WebSocketRestApiResourceConfig.java
index fcbd45c743..087dd3910c 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/WebSocketRestApiResourceConfig.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/WebSocketRestApiResourceConfig.java
@@ -1,8 +1,10 @@
 package bisq.http_api.web_socket;
 
+import bisq.http_api.rest_api.RestApiResourceConfig;
 import bisq.http_api.rest_api.domain.market_price.MarketPriceRestApi;
+import bisq.http_api.rest_api.domain.offer.OfferRestApi;
 import bisq.http_api.rest_api.domain.offerbook.OfferbookRestApi;
-import bisq.http_api.rest_api.RestApiResourceConfig;
+import bisq.http_api.rest_api.domain.trade.TradeRestApi;
 import bisq.http_api.rest_api.domain.user_identity.UserIdentityRestApi;
 import jakarta.ws.rs.ApplicationPath;
 import lombok.extern.slf4j.Slf4j;
@@ -11,8 +13,10 @@
 public class WebSocketRestApiResourceConfig extends RestApiResourceConfig {
     public WebSocketRestApiResourceConfig(String swaggerBaseUrl,
                                           OfferbookRestApi offerbookRestApi,
+                                          OfferRestApi offerRestApi,
+                                          TradeRestApi tradeRestApi,
                                           UserIdentityRestApi userIdentityRestApi ,
                                           MarketPriceRestApi marketPriceRestApi) {
-        super(swaggerBaseUrl, offerbookRestApi, userIdentityRestApi, marketPriceRestApi);
+        super(swaggerBaseUrl, offerbookRestApi, offerRestApi, tradeRestApi, userIdentityRestApi, marketPriceRestApi);
     }
 }
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/WebSocketService.java b/http-api/src/main/java/bisq/http_api/web_socket/WebSocketService.java
index 86a576485a..3fdc020181 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/WebSocketService.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/WebSocketService.java
@@ -25,6 +25,7 @@
 import bisq.http_api.web_socket.util.GrizzlySwaggerHttpHandler;
 import bisq.user.UserService;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import jakarta.ws.rs.core.UriBuilder;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
@@ -116,6 +117,8 @@ public WebSocketService(Config config,
         this.config = config;
         this.restApiResourceConfig = restApiResourceConfig;
         ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.registerModule(new Jdk8Module());
+
         //objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
 
         subscriptionService = new SubscriptionService(objectMapper, bondedRolesService, chatService, userService);
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/domain/BaseWebSocketService.java b/http-api/src/main/java/bisq/http_api/web_socket/domain/BaseWebSocketService.java
index a36cf75919..89c4e12163 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/domain/BaseWebSocketService.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/domain/BaseWebSocketService.java
@@ -19,11 +19,17 @@
 
 
 import bisq.common.application.Service;
+import bisq.dto.account.protocol_type.TradeProtocolTypeDto;
+import bisq.dto.offer.amount.spec.AmountSpecDto;
+import bisq.dto.offer.bisq_easy.OfferListItemDto;
+import bisq.dto.offer.options.OfferOptionDto;
+import bisq.dto.offer.price.spec.PriceSpecDto;
 import bisq.http_api.web_socket.subscription.*;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 
@@ -42,8 +48,40 @@ public BaseWebSocketService(ObjectMapper objectMapper,
 
     abstract public Optional<String> getJsonPayload();
 
+    //todo
     protected <T> Optional<String> toJson(T payload) {
         try {
+            if (payload instanceof List<?> list && list.get(0) instanceof OfferListItemDto offerListItemDto) {
+                try {
+                    PriceSpecDto value = offerListItemDto.getBisqEasyOffer().priceSpec();
+                    objectMapper.writeValueAsString(value);
+                } catch (JsonProcessingException e) {
+                    log.error("Json serialisation failed", e);
+                }
+                try {
+                    AmountSpecDto value = offerListItemDto.getBisqEasyOffer().amountSpec();
+                    objectMapper.writeValueAsString(value);
+                } catch (JsonProcessingException e) {
+                    log.error("Json serialisation failed", e);
+                }
+                try {
+                    List<OfferOptionDto> value = offerListItemDto.getBisqEasyOffer().offerOptions();
+                    objectMapper.writeValueAsString(value);
+                } catch (JsonProcessingException e) {
+                    log.error("Json serialisation failed", e);
+                }
+                try {
+                    List<TradeProtocolTypeDto> value = offerListItemDto.getBisqEasyOffer().protocolTypes();
+                    objectMapper.writeValueAsString(value);
+                } catch (JsonProcessingException e) {
+                    log.error("Json serialisation failed", e); //failed
+                }
+                try {
+                    objectMapper.writeValueAsString(offerListItemDto.getBisqEasyOffer());
+                } catch (JsonProcessingException e) {
+                    log.error("Json serialisation failed", e); //failed
+                }
+            }
             return Optional.of(objectMapper.writeValueAsString(payload));
         } catch (JsonProcessingException e) {
             log.error("Json serialisation failed", e);
@@ -73,7 +111,6 @@ protected void send(String json,
                         Subscriber subscriber,
                         ModificationType modificationType) {
         WebSocketEvent.toJson(objectMapper,
-                        subscriber.getWebSocketEventClassName(),
                         subscriber.getTopic(),
                         subscriber.getSubscriberId(),
                         json,
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/domain/market_price/MarketPriceWebSocketService.java b/http-api/src/main/java/bisq/http_api/web_socket/domain/market_price/MarketPriceWebSocketService.java
index 24e2e5cf1c..8872a2b2b0 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/domain/market_price/MarketPriceWebSocketService.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/domain/market_price/MarketPriceWebSocketService.java
@@ -23,6 +23,8 @@
 import bisq.common.currency.Market;
 import bisq.common.observable.Pin;
 import bisq.common.observable.map.ObservableHashMap;
+import bisq.dto.DtoMappings;
+import bisq.dto.common.monetary.PriceQuoteDto;
 import bisq.http_api.web_socket.domain.SimpleObservableWebSocketService;
 import bisq.http_api.web_socket.subscription.SubscriberRepository;
 import bisq.http_api.web_socket.subscription.Topic;
@@ -34,7 +36,7 @@
 import java.util.stream.Collectors;
 
 @Slf4j
-public class MarketPriceWebSocketService extends SimpleObservableWebSocketService<ObservableHashMap<Market, MarketPrice>, Map<String, Long>> {
+public class MarketPriceWebSocketService extends SimpleObservableWebSocketService<ObservableHashMap<Market, MarketPrice>, Map<String, PriceQuoteDto>> {
     private final MarketPriceService marketPriceService;
 
     public MarketPriceWebSocketService(ObjectMapper objectMapper,
@@ -50,18 +52,23 @@ protected ObservableHashMap<Market, MarketPrice> getObservable() {
     }
 
     @Override
-    protected HashMap<String, Long> toPayload(ObservableHashMap<Market, MarketPrice> observable) {
+    protected HashMap<String, PriceQuoteDto> toPayload(ObservableHashMap<Market, MarketPrice> observable) {
         return getObservable()
                 .entrySet().stream()
-                .filter(entry -> entry.getKey().getBaseCurrencyCode().equals("BTC")) // We get altcoin quotes as well which have BTC as quote currency
+                .filter(MarketPriceWebSocketService::isBaseCurrencyBtc)
                 .collect(Collectors.toMap(
                         entry -> entry.getKey().getQuoteCurrencyCode(),
-                        entry -> entry.getValue().getPriceQuote().getValue(),
+                        entry -> DtoMappings.PriceQuoteMapping.from(entry.getValue().getPriceQuote()),
                         (existing, replacement) -> existing,
                         HashMap::new
                 ));
     }
 
+    private static boolean isBaseCurrencyBtc(Map.Entry<Market, MarketPrice> entry) {
+        // We get altcoin quotes as well which have BTC as quote currency
+        return entry.getKey().getBaseCurrencyCode().equals("BTC");
+    }
+
     @Override
     protected Pin setupObserver() {
         return getObservable().addObserver(this::onChange);
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/domain/offerbook/OffersWebSocketService.java b/http-api/src/main/java/bisq/http_api/web_socket/domain/offerbook/OffersWebSocketService.java
index ea4eb41e6c..6d14d3a09a 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/domain/offerbook/OffersWebSocketService.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/domain/offerbook/OffersWebSocketService.java
@@ -17,43 +17,27 @@
 
 package bisq.http_api.web_socket.domain.offerbook;
 
-import bisq.account.payment_method.PaymentMethod;
 import bisq.bonded_roles.BondedRolesService;
 import bisq.bonded_roles.market_price.MarketPriceService;
 import bisq.chat.ChatService;
 import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannel;
 import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannelService;
 import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookMessage;
-import bisq.http_api.rest_api.domain.offerbook.OfferListItemDto;
-import bisq.http_api.rest_api.domain.offerbook.ReputationScoreDto;
-import bisq.common.currency.Market;
 import bisq.common.observable.Pin;
 import bisq.common.observable.collection.CollectionObserver;
-import bisq.common.util.StringUtils;
+import bisq.dto.OfferListItemDtoFactory;
+import bisq.dto.offer.bisq_easy.OfferListItemDto;
 import bisq.http_api.web_socket.domain.BaseWebSocketService;
 import bisq.http_api.web_socket.subscription.ModificationType;
 import bisq.http_api.web_socket.subscription.SubscriberRepository;
-import bisq.i18n.Res;
-import bisq.offer.Direction;
-import bisq.offer.amount.OfferAmountFormatter;
-import bisq.offer.amount.spec.AmountSpec;
-import bisq.offer.amount.spec.RangeAmountSpec;
-import bisq.offer.bisq_easy.BisqEasyOffer;
-import bisq.offer.payment_method.PaymentMethodSpecUtil;
-import bisq.offer.price.spec.PriceSpec;
-import bisq.offer.price.spec.PriceSpecFormatter;
-import bisq.presentation.formatters.DateFormatter;
 import bisq.user.UserService;
 import bisq.user.identity.UserIdentityService;
-import bisq.user.profile.UserProfile;
 import bisq.user.profile.UserProfileService;
 import bisq.user.reputation.ReputationService;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.base.Joiner;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.NotImplementedException;
 
-import java.text.DateFormat;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
@@ -71,10 +55,10 @@ public class OffersWebSocketService extends BaseWebSocketService {
     private final Set<Pin> pins = new HashSet<>();
 
     public OffersWebSocketService(ObjectMapper objectMapper,
-                                     SubscriberRepository subscriberRepository,
-                                     ChatService chatService,
-                                     UserService userService,
-                                     BondedRolesService bondedRolesService) {
+                                  SubscriberRepository subscriberRepository,
+                                  ChatService chatService,
+                                  UserService userService,
+                                  BondedRolesService bondedRolesService) {
         super(objectMapper, subscriberRepository, OFFERS);
 
         bisqEasyOfferbookChannelService = chatService.getBisqEasyOfferbookChannelService();
@@ -127,15 +111,15 @@ public Optional<String> getJsonPayload(Stream<BisqEasyOfferbookChannel> channels
         ArrayList<OfferListItemDto> payload = channels
                 .flatMap(channel ->
                         channel.getChatMessages().stream()
-                                .map(this::toOfferListItemDto))
+                                .map(this::createOfferListItemDto))
                 .collect(Collectors.toCollection(ArrayList::new));
         return toJson(payload);
     }
 
     private void send(String quoteCurrencyCode,
-                      BisqEasyOfferbookMessage message,
+                      BisqEasyOfferbookMessage bisqEasyOfferbookMessage,
                       ModificationType modificationType) {
-        OfferListItemDto item = toOfferListItemDto(message);
+        OfferListItemDto item = createOfferListItemDto(bisqEasyOfferbookMessage);
         // The payload is defined as a list to support batch data delivery at subscribe.
         ArrayList<OfferListItemDto> payload = new ArrayList<>(List.of(item));
         toJson(payload).ifPresent(json -> {
@@ -145,78 +129,11 @@ private void send(String quoteCurrencyCode,
         });
     }
 
-    private OfferListItemDto toOfferListItemDto(BisqEasyOfferbookMessage message) {
-        BisqEasyOffer bisqEasyOffer = message.getBisqEasyOffer().orElseThrow();
-        Market market = bisqEasyOffer.getMarket();
-
-        long date = message.getDate();
-        String formattedDate = DateFormatter.formatDateTime(new Date(date), DateFormat.MEDIUM, DateFormat.SHORT,
-                true, " " + Res.get("temporal.at") + " ");
-        String authorUserProfileId = message.getAuthorUserProfileId();
-        Optional<UserProfile> senderUserProfile = userProfileService.findUserProfile(authorUserProfileId);
-        String nym = senderUserProfile.map(UserProfile::getNym).orElse("");
-        String userName = senderUserProfile.map(UserProfile::getUserName).orElse("");
-
-        ReputationScoreDto reputationScore = senderUserProfile.flatMap(reputationService::findReputationScore)
-                .map(score -> new ReputationScoreDto(
-                        score.getTotalScore(),
-                        score.getFiveSystemScore(),
-                        score.getRanking()
-                ))
-                .orElse(new ReputationScoreDto(0, 0, 0));
-        AmountSpec amountSpec = bisqEasyOffer.getAmountSpec();
-        PriceSpec priceSpec = bisqEasyOffer.getPriceSpec();
-        boolean hasAmountRange = amountSpec instanceof RangeAmountSpec;
-        String formattedQuoteAmount = OfferAmountFormatter.formatQuoteAmount(
+    private OfferListItemDto createOfferListItemDto(BisqEasyOfferbookMessage bisqEasyOfferbookMessage) {
+        return OfferListItemDtoFactory.createOfferListItemDto(userProfileService,
+                userIdentityService,
+                reputationService,
                 marketPriceService,
-                amountSpec,
-                priceSpec,
-                market,
-                hasAmountRange,
-                true
-        );
-        String formattedPrice = PriceSpecFormatter.getFormattedPriceSpec(priceSpec, true);
-
-        List<String> quoteSidePaymentMethods = PaymentMethodSpecUtil.getPaymentMethods(bisqEasyOffer.getQuoteSidePaymentMethodSpecs())
-                .stream()
-                .map(PaymentMethod::getName)
-                .collect(Collectors.toList());
-
-        List<String> baseSidePaymentMethods = PaymentMethodSpecUtil.getPaymentMethods(bisqEasyOffer.getBaseSidePaymentMethodSpecs())
-                .stream()
-                .map(PaymentMethod::getName)
-                .collect(Collectors.toList());
-
-        String supportedLanguageCodes = Joiner.on(",").join(bisqEasyOffer.getSupportedLanguageCodes());
-        boolean isMyMessage = message.isMyMessage(userIdentityService);
-        Direction direction = bisqEasyOffer.getDirection();
-        String offerTitle = getOfferTitle(message, direction, isMyMessage);
-        String messageId = message.getId();
-        String offerId = bisqEasyOffer.getId();
-        return new OfferListItemDto(messageId,
-                offerId,
-                isMyMessage,
-                direction,
-                market.getQuoteCurrencyCode(),
-                offerTitle,
-                date,
-                formattedDate,
-                nym,
-                userName,
-                reputationScore,
-                formattedQuoteAmount,
-                formattedPrice,
-                quoteSidePaymentMethods,
-                baseSidePaymentMethods,
-                supportedLanguageCodes);
-    }
-
-    private String getOfferTitle(BisqEasyOfferbookMessage message, Direction direction, boolean isMyMessage) {
-        if (isMyMessage) {
-            String directionString = StringUtils.capitalize(Res.get("offer." + direction.name().toLowerCase()));
-            return Res.get("bisqEasy.tradeWizard.review.chatMessage.myMessageTitle", directionString);
-        } else {
-            return message.getText();
-        }
+                bisqEasyOfferbookMessage);
     }
 }
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiRequest.java b/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiRequest.java
index 011352bfb9..95ef61d76f 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiRequest.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiRequest.java
@@ -17,6 +17,7 @@
 
 package bisq.http_api.web_socket.rest_api_proxy;
 
+import bisq.http_api.web_socket.WebSocketMessage;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.EqualsAndHashCode;
@@ -29,15 +30,13 @@
 @Getter
 @EqualsAndHashCode
 @ToString
-public class WebSocketRestApiRequest {
+public class WebSocketRestApiRequest implements WebSocketMessage {
     // Client side full qualified class name for response class required for polymorphism support
     private String responseClassName;
     private String requestId;
     private String path;
     private String method;
     private String body;
-    // Client side full qualified class name set by serialize to support polymorphism
-    private String className;
 
     public static boolean isExpectedJson(String message) {
         return message.contains("requestId") &&
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiResponse.java b/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiResponse.java
index dd416833e5..efc8324784 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiResponse.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiResponse.java
@@ -17,6 +17,7 @@
 
 package bisq.http_api.web_socket.rest_api_proxy;
 
+import bisq.http_api.web_socket.WebSocketMessage;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -32,19 +33,15 @@
 @Getter
 @EqualsAndHashCode
 @ToString
-public class WebSocketRestApiResponse {
-    // Client side full qualified class name required for polymorphism support
-    private final String className;
+public class WebSocketRestApiResponse implements WebSocketMessage {
     private final String requestId;
     private final int statusCode;
     private final String body;
 
     @JsonCreator
-    public WebSocketRestApiResponse(@JsonProperty("className") String className,
-                                    @JsonProperty("requestId") String requestId,
+    public WebSocketRestApiResponse(@JsonProperty("requestId") String requestId,
                                     @JsonProperty("statusCode") int statusCode,
                                     @JsonProperty("body") String body) {
-        this.className = className;
         this.requestId = requestId;
         this.statusCode = statusCode;
         this.body = body;
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiService.java b/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiService.java
index bcf9af8e8b..f07da42daa 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiService.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/rest_api_proxy/WebSocketRestApiService.java
@@ -20,6 +20,7 @@
 import bisq.common.application.Service;
 import bisq.http_api.web_socket.util.JsonUtil;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.ws.rs.core.Response;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.ToString;
@@ -76,7 +77,7 @@ private WebSocketRestApiResponse sendToRestApiServer(WebSocketRestApiRequest req
         String errorMessage = RequestValidation.validateRequest(request);
         if (errorMessage != null) {
             log.error(errorMessage);
-            return new WebSocketRestApiResponse(request.getResponseClassName(), request.getRequestId(), 400, errorMessage);
+            return new WebSocketRestApiResponse(request.getRequestId(), Response.Status.BAD_REQUEST.getStatusCode(), errorMessage);
         }
 
         String url = restApiAddress + request.getPath();
@@ -91,14 +92,13 @@ private WebSocketRestApiResponse sendToRestApiServer(WebSocketRestApiRequest req
             HttpRequest httpRequest = requestBuilder.build();
             log.info("Send {} httpRequest to {}. httpRequest={} ", method, url, httpRequest);
             // Blocking send
-            HttpClient httpClient1 = httpClient.orElseThrow();
-            HttpResponse<String> httpResponse = httpClient1.send(httpRequest, HttpResponse.BodyHandlers.ofString());
+            HttpResponse<String> httpResponse = httpClient.orElseThrow().send(httpRequest, HttpResponse.BodyHandlers.ofString());
             log.info("httpResponse {}", httpResponse);
-            return new WebSocketRestApiResponse(request.getResponseClassName(), request.getRequestId(), httpResponse.statusCode(), httpResponse.body());
+            return new WebSocketRestApiResponse( request.getRequestId(), httpResponse.statusCode(), httpResponse.body());
         } catch (Exception e) {
             errorMessage = String.format("Error at sending a '%s' request to '%s' with body: '%s'. Error: %s", method, url, body, e.getMessage());
             log.error(errorMessage, e);
-            return new WebSocketRestApiResponse(request.getResponseClassName(), request.getRequestId(), 500, errorMessage);
+            return new WebSocketRestApiResponse(request.getRequestId(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), errorMessage);
         }
     }
 }
\ No newline at end of file
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/subscription/Subscriber.java b/http-api/src/main/java/bisq/http_api/web_socket/subscription/Subscriber.java
index 7ba2f9c898..bf88566cd3 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/subscription/Subscriber.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/subscription/Subscriber.java
@@ -37,20 +37,17 @@ public class Subscriber {
     private final Optional<String> parameter;
     private final String subscriberId;
     private final WebSocket webSocket;
-    private final String webSocketEventClassName;
     private final AtomicInteger sequenceNumber = new AtomicInteger(0); // sequenceNumber start with 0 at subscribe time and gets increased at each emitted WebSocketEvent
     private final ExecutorService executorService;
 
     public Subscriber(Topic topic,
                       Optional<String> parameter,
                       String subscriberId,
-                      WebSocket webSocket,
-                      String webSocketEventClassName) {
+                      WebSocket webSocket) {
         this.topic = topic;
         this.parameter = parameter;
         this.subscriberId = subscriberId;
         this.webSocket = webSocket;
-        this.webSocketEventClassName = webSocketEventClassName;
         executorService = ExecutorFactory.newSingleThreadExecutor("Subscriber-" + topic.name() + "-" + subscriberId);
     }
 
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriberRepository.java b/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriberRepository.java
index 94890c918a..d772e035a2 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriberRepository.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriberRepository.java
@@ -39,7 +39,7 @@ public void onConnectionClosed(WebSocket webSocket) {
     public void add(SubscriptionRequest request, WebSocket webSocket) {
         Topic topic = request.getTopic();
         Optional<String> parameter = StringUtils.toOptional(request.getParameter());
-        Subscriber subscriber = new Subscriber(topic, parameter, request.getRequestId(), webSocket, request.getWebSocketEventClassName());
+        Subscriber subscriber = new Subscriber(topic, parameter, request.getRequestId(), webSocket);
         synchronized (subscribersByTopicLock) {
             Set<Subscriber> subscribers = subscribersByTopic.computeIfAbsent(topic, key -> new HashSet<>());
             subscribers.add(subscriber);
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionRequest.java b/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionRequest.java
index 86e8b26e72..6311845c8b 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionRequest.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionRequest.java
@@ -17,6 +17,7 @@
 
 package bisq.http_api.web_socket.subscription;
 
+import bisq.http_api.web_socket.WebSocketMessage;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.EqualsAndHashCode;
@@ -31,20 +32,12 @@
 @Getter
 @EqualsAndHashCode
 @ToString
-public class SubscriptionRequest {
-    // Client side full qualified class name for response class required for polymorphism support
-    private String responseClassName;
-    // Client side full qualified class name for WebSocketEvent class required for polymorphism support
-    private String webSocketEventClassName;
+public class SubscriptionRequest implements WebSocketMessage {
     private String requestId;
     private Topic topic;
     @Nullable
     private String parameter;
 
-    // Client side full qualified class name set by serialize to support polymorphism
-    private String className;
-
-
     public static Optional<SubscriptionRequest> fromJson(ObjectMapper objectMapper, String json) {
         try {
             return Optional.of(objectMapper.readValue(json, SubscriptionRequest.class));
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionResponse.java b/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionResponse.java
index fb2973e058..fca4121ff4 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionResponse.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionResponse.java
@@ -17,6 +17,7 @@
 
 package bisq.http_api.web_socket.subscription;
 
+import bisq.http_api.web_socket.WebSocketMessage;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -34,9 +35,7 @@
 @Getter
 @EqualsAndHashCode
 @ToString
-public class SubscriptionResponse {
-    // Client side full qualified class name required for polymorphism support
-    private final String className;
+public class SubscriptionResponse implements WebSocketMessage {
     private final String requestId;
     @Nullable
     private final String payload;
@@ -44,11 +43,9 @@ public class SubscriptionResponse {
     private final String errorMessage;
 
     @JsonCreator
-    public SubscriptionResponse(@JsonProperty("className") String className,
-                                @JsonProperty("requestId") String requestId,
+    public SubscriptionResponse(@JsonProperty("requestId") String requestId,
                                 @JsonProperty("payload") @Nullable String payload,
                                 @JsonProperty("errorMessage") @Nullable String errorMessage) {
-        this.className = className;
         this.requestId = requestId;
         this.payload = payload;
         this.errorMessage = errorMessage;
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionService.java b/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionService.java
index 1a31e995db..f69d20ae1c 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionService.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/subscription/SubscriptionService.java
@@ -87,7 +87,7 @@ private void subscribe(SubscriptionRequest request, WebSocket webSocket) {
 
         findWebSocketService(request.getTopic())
                 .flatMap(BaseWebSocketService::getJsonPayload)
-                .flatMap(json -> new SubscriptionResponse(request.getResponseClassName(), request.getRequestId(), json, null)
+                .flatMap(json -> new SubscriptionResponse(request.getRequestId(), json, null)
                         .toJson(objectMapper))
                 .ifPresent(webSocket::send);
     }
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/subscription/WebSocketEvent.java b/http-api/src/main/java/bisq/http_api/web_socket/subscription/WebSocketEvent.java
index 0130a7b387..24fcd29e24 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/subscription/WebSocketEvent.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/subscription/WebSocketEvent.java
@@ -17,6 +17,7 @@
 
 package bisq.http_api.web_socket.subscription;
 
+import bisq.http_api.web_socket.WebSocketMessage;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -32,9 +33,7 @@
 @Getter
 @EqualsAndHashCode
 @ToString
-public class WebSocketEvent {
-    // Client side full qualified class name required for polymorphism support
-    private final String className;
+public class WebSocketEvent implements WebSocketMessage {
     private final Topic topic;
     private final String subscriberId;
     private final String payload;
@@ -42,13 +41,11 @@ public class WebSocketEvent {
     private final int sequenceNumber;
 
     @JsonCreator
-    public WebSocketEvent(@JsonProperty("className") String className,
-                          @JsonProperty("topic") Topic topic,
+    public WebSocketEvent(@JsonProperty("topic") Topic topic,
                           @JsonProperty("subscriberId") String subscriberId,
                           @JsonProperty("payload") String payload,
                           @JsonProperty("modificationType") ModificationType modificationType,
                           @JsonProperty("sequenceNumber") int sequenceNumber) {
-        this.className = className;
         this.topic = topic;
         this.subscriberId = subscriberId;
         this.payload = payload;
@@ -57,14 +54,13 @@ public WebSocketEvent(@JsonProperty("className") String className,
     }
 
     public static Optional<String> toJson(ObjectMapper objectMapper,
-                                          String className,
                                           Topic topic,
                                           String subscriberId,
                                           String payload,
                                           ModificationType modificationType,
                                           int sequenceNumber) {
         try {
-            var webSocketEvent = new WebSocketEvent(className, topic, subscriberId, payload, modificationType, sequenceNumber);
+            var webSocketEvent = new WebSocketEvent(topic, subscriberId, payload, modificationType, sequenceNumber);
             return Optional.of(objectMapper.writeValueAsString(webSocketEvent));
         } catch (JsonProcessingException e) {
             log.error("Json serialisation failed", e);
diff --git a/http-api/src/main/java/bisq/http_api/web_socket/util/JsonUtil.java b/http-api/src/main/java/bisq/http_api/web_socket/util/JsonUtil.java
index 7b6b4b7986..92203549eb 100644
--- a/http-api/src/main/java/bisq/http_api/web_socket/util/JsonUtil.java
+++ b/http-api/src/main/java/bisq/http_api/web_socket/util/JsonUtil.java
@@ -21,14 +21,15 @@
 import java.util.regex.Pattern;
 
 public class JsonUtil {
-    // We use by convention same class name. We get the className field set by the client.
+    // We use by convention same class name. We get the type field set by the client.
     public static boolean hasExpectedJsonClassName(Class<?> clazz, String json) {
-        String regex = "\"className\":\"[^\"]*\\.([^\"]+)\"";
+        String regex = "\"type\":\\s*\"([^\"]+)\""; // We use simple name
         Pattern pattern = Pattern.compile(regex);
         Matcher matcher = pattern.matcher(json);
         if (matcher.find()) {
-            String className = matcher.group(1);
-            return clazz.getSimpleName().equals(className);
+            String type = matcher.group(1);
+            String simpleName = clazz.getSimpleName();
+            return simpleName.equals(type);
         } else {
             return false;
         }
diff --git a/offer/src/main/java/bisq/offer/amount/OfferAmountFormatter.java b/offer/src/main/java/bisq/offer/amount/OfferAmountFormatter.java
index 1877db2bbf..bfc2413d9c 100644
--- a/offer/src/main/java/bisq/offer/amount/OfferAmountFormatter.java
+++ b/offer/src/main/java/bisq/offer/amount/OfferAmountFormatter.java
@@ -28,7 +28,7 @@
 import bisq.presentation.formatters.AmountFormatter;
 import lombok.extern.slf4j.Slf4j;
 
-import java.util.function.Function;
+import java.util.function.BiFunction;
 
 @Slf4j
 public class OfferAmountFormatter {
@@ -39,11 +39,11 @@ public class OfferAmountFormatter {
 
     // Either min-max or fixed
     public static String formatBaseAmount(MarketPriceService marketPriceService, Offer<?, ?> offer) {
-        return formatBaseAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), offer.hasAmountRange(), true);
+        return formatBaseAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), offer.hasAmountRange(), true, true);
     }
 
     public static String formatBaseAmount(MarketPriceService marketPriceService, Offer<?, ?> offer, boolean withCode) {
-        return formatBaseAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), offer.hasAmountRange(), withCode);
+        return formatBaseAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), offer.hasAmountRange(), withCode, true);
     }
 
     public static String formatBaseAmount(MarketPriceService marketPriceService,
@@ -51,11 +51,12 @@ public static String formatBaseAmount(MarketPriceService marketPriceService,
                                           PriceSpec priceSpec,
                                           Market market,
                                           boolean hasAmountRange,
-                                          boolean withCode) {
+                                          boolean withCode,
+                                          boolean useLowPrecision) {
         if (hasAmountRange) {
-            return formatBaseSideRangeAmount(marketPriceService, amountSpec, priceSpec, market, withCode);
+            return formatBaseSideRangeAmount(marketPriceService, amountSpec, priceSpec, market, withCode, useLowPrecision);
         } else {
-            return formatBaseSideFixedAmount(marketPriceService, amountSpec, priceSpec, market, withCode);
+            return formatBaseSideFixedAmount(marketPriceService, amountSpec, priceSpec, market, withCode, useLowPrecision);
         }
     }
 
@@ -67,15 +68,18 @@ public static String formatBaseSideFixedAmount(MarketPriceService marketPriceSer
     public static String formatBaseSideFixedAmount(MarketPriceService marketPriceService,
                                                    Offer<?, ?> offer,
                                                    boolean withCode) {
-        return formatBaseSideFixedAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), withCode);
+        return formatBaseSideFixedAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), withCode, true);
     }
 
     public static String formatBaseSideFixedAmount(MarketPriceService marketPriceService,
                                                    AmountSpec amountSpec,
                                                    PriceSpec priceSpec,
                                                    Market market,
-                                                   boolean withCode) {
-        return OfferAmountUtil.findBaseSideFixedAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+                                                   boolean withCode,
+                                                   boolean useLowPrecision) {
+        return OfferAmountUtil.findBaseSideFixedAmount(marketPriceService, amountSpec, priceSpec, market)
+                .map(monetary -> getFormatFunction(withCode).apply(monetary, useLowPrecision))
+                .orElse(Res.get("data.na"));
     }
 
     // Min
@@ -94,7 +98,9 @@ public static String formatBaseSideMinAmount(MarketPriceService marketPriceServi
                                                  PriceSpec priceSpec,
                                                  Market market,
                                                  boolean withCode) {
-        return OfferAmountUtil.findBaseSideMinAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+        return OfferAmountUtil.findBaseSideMinAmount(marketPriceService, amountSpec, priceSpec, market)
+                .map(monetary -> getFormatFunction(withCode).apply(monetary, true))
+                .orElse(Res.get("data.na"));
     }
 
     // Max
@@ -113,36 +119,43 @@ public static String formatBaseSideMaxAmount(MarketPriceService marketPriceServi
                                                  PriceSpec priceSpec,
                                                  Market market,
                                                  boolean withCode) {
-        return OfferAmountUtil.findBaseSideMaxAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+        return OfferAmountUtil.findBaseSideMaxAmount(marketPriceService, amountSpec, priceSpec, market)
+                .map(monetary -> getFormatFunction(withCode).apply(monetary, true))
+                .orElse(Res.get("data.na"));
     }
 
     // Max or fixed
     public static String formatBaseSideMaxOrFixedAmount(MarketPriceService marketPriceService,
                                                         Offer<?, ?> offer,
-                                                        boolean withCode) {
-        return formatBaseSideMaxOrFixedAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), withCode);
+                                                        boolean withCode,
+                                                        boolean useLowPrecision) {
+        return formatBaseSideMaxOrFixedAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), withCode, useLowPrecision);
     }
 
     public static String formatBaseSideMaxOrFixedAmount(MarketPriceService marketPriceService,
                                                         AmountSpec amountSpec,
                                                         PriceSpec priceSpec,
                                                         Market market,
-                                                        boolean withCode) {
-        return OfferAmountUtil.findBaseSideMaxOrFixedAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+                                                        boolean withCode,
+                                                        boolean useLowPrecision) {
+        return OfferAmountUtil.findBaseSideMaxOrFixedAmount(marketPriceService, amountSpec, priceSpec, market)
+                .map(monetary -> getFormatFunction(withCode).apply(monetary, useLowPrecision))
+                .orElse(Res.get("data.na"));
     }
 
     // Range (Min - Max)
     public static String formatBaseSideRangeAmount(MarketPriceService marketPriceService,
                                                    Offer<?, ?> offer,
                                                    boolean withCode) {
-        return formatBaseSideRangeAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), withCode);
+        return formatBaseSideRangeAmount(marketPriceService, offer.getAmountSpec(), offer.getPriceSpec(), offer.getMarket(), withCode, true);
     }
 
     public static String formatBaseSideRangeAmount(MarketPriceService marketPriceService,
                                                    AmountSpec amountSpec,
                                                    PriceSpec priceSpec,
                                                    Market market,
-                                                   boolean withCode) {
+                                                   boolean withCode,
+                                                   boolean useLowPrecision) {
         return formatBaseSideMinAmount(marketPriceService, amountSpec, priceSpec, market, false) + " - " +
                 formatBaseSideMaxAmount(marketPriceService, amountSpec, priceSpec, market, withCode);
     }
@@ -198,7 +211,9 @@ public static String formatQuoteSideFixedAmount(MarketPriceService marketPriceSe
                                                     PriceSpec priceSpec,
                                                     Market market,
                                                     boolean withCode) {
-        return OfferAmountUtil.findQuoteSideFixedAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+        return OfferAmountUtil.findQuoteSideFixedAmount(marketPriceService, amountSpec, priceSpec, market)
+                .map(monetary -> getFormatFunction(withCode).apply(monetary, true))
+                .orElse(Res.get("data.na"));
     }
 
     // Min
@@ -217,7 +232,9 @@ public static String formatQuoteSideMinAmount(MarketPriceService marketPriceServ
                                                   PriceSpec priceSpec,
                                                   Market market,
                                                   boolean withCode) {
-        return OfferAmountUtil.findQuoteSideMinAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+        return OfferAmountUtil.findQuoteSideMinAmount(marketPriceService, amountSpec, priceSpec, market)
+                .map(monetary -> getFormatFunction(withCode).apply(monetary, true))
+                .orElse(Res.get("data.na"));
     }
 
     // Min or fixed
@@ -236,7 +253,9 @@ public static String formatQuoteSideMinOrFixedAmount(MarketPriceService marketPr
                                                          PriceSpec priceSpec,
                                                          Market market,
                                                          boolean withCode) {
-        return OfferAmountUtil.findQuoteSideMinOrFixedAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+        return OfferAmountUtil.findQuoteSideMinOrFixedAmount(marketPriceService, amountSpec, priceSpec, market)
+                .map(monetary -> getFormatFunction(withCode).apply(monetary, true))
+                .orElse(Res.get("data.na"));
     }
 
     // Max
@@ -255,7 +274,9 @@ public static String formatQuoteSideMaxAmount(MarketPriceService marketPriceServ
                                                   PriceSpec priceSpec,
                                                   Market market,
                                                   boolean withCode) {
-        return OfferAmountUtil.findQuoteSideMaxAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+        return OfferAmountUtil.findQuoteSideMaxAmount(marketPriceService, amountSpec, priceSpec, market)
+                .map(monetary -> getFormatFunction(withCode).apply(monetary, true))
+                .orElse(Res.get("data.na"));
     }
 
     // Max or fixed
@@ -270,7 +291,7 @@ public static String formatQuoteSideMaxOrFixedAmount(MarketPriceService marketPr
                                                          PriceSpec priceSpec,
                                                          Market market,
                                                          boolean withCode) {
-        return OfferAmountUtil.findQuoteSideMaxOrFixedAmount(marketPriceService, amountSpec, priceSpec, market).map(getFormatFunction(withCode)).orElse(Res.get("data.na"));
+        return OfferAmountUtil.findQuoteSideMaxOrFixedAmount(marketPriceService, amountSpec, priceSpec, market).map(monetary -> getFormatFunction(withCode).apply(monetary, true)).orElse(Res.get("data.na"));
     }
 
     // Range (Min - Max)
@@ -294,7 +315,9 @@ public static String formatQuoteSideRangeAmount(MarketPriceService marketPriceSe
     // Private
     ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private static Function<Monetary, String> getFormatFunction(boolean withCode) {
-        return withCode ? AmountFormatter::formatAmountWithCode : AmountFormatter::formatAmount;
+    private static BiFunction<Monetary, Boolean, String> getFormatFunction(boolean withCode) {
+        BiFunction<Monetary, Boolean, String> formatAmount = AmountFormatter::formatAmount;
+        BiFunction<Monetary, Boolean, String> formatAmountWithCode = AmountFormatter::formatAmountWithCode;
+        return withCode ? formatAmountWithCode : formatAmount;
     }
 }
diff --git a/offer/src/main/java/bisq/offer/bisq_easy/BisqEasyOffer.java b/offer/src/main/java/bisq/offer/bisq_easy/BisqEasyOffer.java
index a77a1d568b..be58de5e2b 100644
--- a/offer/src/main/java/bisq/offer/bisq_easy/BisqEasyOffer.java
+++ b/offer/src/main/java/bisq/offer/bisq_easy/BisqEasyOffer.java
@@ -78,7 +78,7 @@ public BisqEasyOffer(NetworkId makerNetworkId,
         );
     }
 
-    private BisqEasyOffer(String id,
+    public BisqEasyOffer(String id,
                           long date,
                           NetworkId makerNetworkId,
                           Direction direction,
@@ -101,7 +101,9 @@ private BisqEasyOffer(String id,
                 baseSidePaymentMethodSpecs,
                 quoteSidePaymentMethodSpecs,
                 offerOptions);
-        this.supportedLanguageCodes = supportedLanguageCodes;
+
+        // We might get an immutable list, but we need to sort it, so wrap it into an ArrayList
+        this.supportedLanguageCodes = new ArrayList<>(supportedLanguageCodes);
         Collections.sort(this.supportedLanguageCodes);
 
         verify();
diff --git a/offer/src/main/java/bisq/offer/payment_method/PaymentMethodSpecUtil.java b/offer/src/main/java/bisq/offer/payment_method/PaymentMethodSpecUtil.java
index bf83b16a04..0398e287b5 100644
--- a/offer/src/main/java/bisq/offer/payment_method/PaymentMethodSpecUtil.java
+++ b/offer/src/main/java/bisq/offer/payment_method/PaymentMethodSpecUtil.java
@@ -17,16 +17,22 @@
 
 package bisq.offer.payment_method;
 
-import bisq.account.payment_method.BitcoinPaymentMethod;
-import bisq.account.payment_method.BitcoinPaymentRail;
-import bisq.account.payment_method.FiatPaymentMethod;
-import bisq.account.payment_method.PaymentMethod;
+import bisq.account.payment_method.*;
 
 import java.util.Collection;
 import java.util.List;
 import java.util.stream.Collectors;
 
 public class PaymentMethodSpecUtil {
+    public static BitcoinPaymentMethod getBitcoinPaymentMethod(String paymentMethod) {
+        return BitcoinPaymentMethodUtil.getPaymentMethod(paymentMethod);
+    }
+
+    public static FiatPaymentMethod getFiatPaymentMethod(String paymentMethod) {
+        return FiatPaymentMethodUtil.getPaymentMethod(paymentMethod);
+    }
+
+
     public static List<BitcoinPaymentMethodSpec> createBitcoinPaymentMethodSpecs(List<BitcoinPaymentMethod> paymentMethods) {
         return paymentMethods.stream()
                 .map(BitcoinPaymentMethodSpec::new)
diff --git a/trade/src/main/java/bisq/trade/bisq_easy/BisqEasyTradeService.java b/trade/src/main/java/bisq/trade/bisq_easy/BisqEasyTradeService.java
index 56222c0c92..ba66e568d8 100644
--- a/trade/src/main/java/bisq/trade/bisq_easy/BisqEasyTradeService.java
+++ b/trade/src/main/java/bisq/trade/bisq_easy/BisqEasyTradeService.java
@@ -229,7 +229,7 @@ public BisqEasyProtocol createBisqEasyProtocol(Identity takerIdentity,
                                                    BitcoinPaymentMethodSpec bitcoinPaymentMethodSpec,
                                                    FiatPaymentMethodSpec fiatPaymentMethodSpec,
                                                    Optional<UserProfile> mediator,
-                                                   PriceSpec agreedPriceSpec,
+                                                   PriceSpec priceSpec,
                                                    long marketPrice) {
         verifyTradingNotOnHalt();
         verifyMinVersionForTrading();
@@ -244,7 +244,7 @@ public BisqEasyProtocol createBisqEasyProtocol(Identity takerIdentity,
                 bitcoinPaymentMethodSpec,
                 fiatPaymentMethodSpec,
                 mediator,
-                agreedPriceSpec,
+                priceSpec,
                 marketPrice);
         boolean isBuyer = bisqEasyOffer.getTakersDirection().isBuy();
         NetworkId makerNetworkId = contract.getMaker().getNetworkId();
diff --git a/trade/src/main/java/bisq/trade/bisq_easy/protocol/messages/BisqEasyTakeOfferRequestHandler.java b/trade/src/main/java/bisq/trade/bisq_easy/protocol/messages/BisqEasyTakeOfferRequestHandler.java
index 26f4bb8514..5a3d45293e 100644
--- a/trade/src/main/java/bisq/trade/bisq_easy/protocol/messages/BisqEasyTakeOfferRequestHandler.java
+++ b/trade/src/main/java/bisq/trade/bisq_easy/protocol/messages/BisqEasyTakeOfferRequestHandler.java
@@ -150,7 +150,7 @@ private void validateAmount(BisqEasyOffer takersOffer, BisqEasyContract takersCo
         Market market = takersOffer.getMarket();
         MarketPrice marketPrice = marketPriceService.getMarketPriceByCurrencyMap().get(market);
         Optional<PriceQuote> priceQuote = PriceUtil.findQuote(marketPriceService,
-                takersContract.getAgreedPriceSpec(), market);
+                takersContract.getPriceSpec(), market);
         Optional<Monetary> amount = priceQuote.map(quote -> quote.toBaseSideMonetary(Monetary.from(takersContract.getQuoteSideAmount(),
                 market.getQuoteCurrencyCode())));
 
diff --git a/user/src/main/java/bisq/user/profile/UserProfile.java b/user/src/main/java/bisq/user/profile/UserProfile.java
index 632e4e1325..547b66a089 100644
--- a/user/src/main/java/bisq/user/profile/UserProfile.java
+++ b/user/src/main/java/bisq/user/profile/UserProfile.java
@@ -133,7 +133,7 @@ private UserProfile(String nickName,
                 ApplicationVersion.getVersion().getVersionAsString());
     }
 
-    private UserProfile(int version,
+    public UserProfile(int version,
                         String nickName,
                         ProofOfWork proofOfWork,
                         int avatarVersion,