diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
index 059e4b60bbecc5761d50b6f6ef0d103ef35f0ff5..4ab94e824c9c401f239439d1cfa234a166e81c80 100644
--- a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
+++ b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
@@ -1690,6 +1690,119 @@
            <arg type="t" name="dataTransferId" direction="in"/>
        </method>
 
+       <method name="startConversation" tp:name-for-bindings="startConversation">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Start a new conversation
+           </tp:docstring>
+           <arg type="s" name="conversationId" direction="out"/>
+           <arg type="s" name="accountId" direction="in"/>
+       </method>
+
+       <method name="acceptConversationRequest" tp:name-for-bindings="acceptConversationRequest">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Accept a conversation's request
+           </tp:docstring>
+           <arg type="s" name="accountId" direction="in"/>
+           <arg type="s" name="conversationId" direction="in"/>
+       </method>
+
+       <method name="declineConversationRequest" tp:name-for-bindings="declineConversationRequest">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Decline a conversation's request
+           </tp:docstring>
+           <arg type="s" name="accountId" direction="in"/>
+           <arg type="s" name="conversationId" direction="in"/>
+       </method>
+
+       <method name="removeConversation" tp:name-for-bindings="removeConversation">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Remove a conversation
+           </tp:docstring>
+           <arg type="b" name="success" direction="out"/>
+           <arg type="s" name="accountId" direction="in"/>
+           <arg type="s" name="conversationId" direction="in"/>
+       </method>
+
+       <method name="getConversations" tp:name-for-bindings="getConversations">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Get the conversation list
+           </tp:docstring>
+           <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorString"/>
+           <arg type="as" name="conversations" direction="out"/>
+           <arg type="s" name="accountId" direction="in"/>
+       </method>
+
+       <method name="getConversationRequests" tp:name-for-bindings="getConversationRequests">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Get the conversation's requests list
+           </tp:docstring>
+           <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/>
+           <arg type="aa{ss}" name="conversations" direction="out"/>
+           <arg type="s" name="accountId" direction="in"/>
+       </method>
+
+       <method name="addConversationMember" tp:name-for-bindings="addConversationMember">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Add a member to a conversation
+           </tp:docstring>
+           <arg type="b" name="success" direction="out"/>
+           <arg type="s" name="accountId" direction="in"/>
+           <arg type="s" name="conversationId" direction="in"/>
+           <arg type="s" name="contactUri" direction="in"/>
+       </method>
+
+       <method name="removeConversationMember" tp:name-for-bindings="removeConversationMember">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Remove a member from a conversation
+           </tp:docstring>
+           <arg type="b" name="success" direction="out"/>
+           <arg type="s" name="accountId" direction="in"/>
+           <arg type="s" name="conversationId" direction="in"/>
+           <arg type="s" name="contactUri" direction="in"/>
+       </method>
+
+       <method name="getConversationMembers" tp:name-for-bindings="getConversationMembers">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Get members of a conversation
+           </tp:docstring>
+           <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/>
+           <arg type="aa{ss}" name="members" direction="out"/>
+           <arg type="s" name="accountId" direction="in"/>
+           <arg type="s" name="conversationId" direction="in"/>
+       </method>
+
+       <method name="sendMessage" tp:name-for-bindings="sendMessage">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Add a message to a conversation
+           </tp:docstring>
+           <arg type="s" name="accountId" direction="in"/>
+           <arg type="s" name="conversationId" direction="in"/>
+           <arg type="s" name="message" direction="in"/>
+           <arg type="s" name="parent" direction="in"/>
+       </method>
+
+       <method name="loadConversationMessages" tp:name-for-bindings="loadConversationMessages">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Load messages from a conversation
+           </tp:docstring>
+           <arg type="s" name="accountId" direction="in"/>
+           <arg type="s" name="conversationId" direction="in"/>
+           <arg type="s" name="fromMessage" direction="in"/>
+           <arg type="u" name="n" direction="in"/>
+           <arg type="u" name="id" direction="out"/>
+       </method>
+
        <signal name="mediaParametersChanged" tp:name-for-bindings="mediaParametersChanged">
            <tp:added version="2.3.0"/>
            <tp:docstring>
@@ -1748,6 +1861,97 @@
            </arg>
        </signal>
 
+       <signal name="conversationLoaded" tp:name-for-bindings="conversationLoaded">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Notify clients when a conversation is loaded
+           </tp:docstring>
+           <arg type="u" name="id">
+               <tp:docstring>
+                   Id of the related loadConversationMessages's request
+               </tp:docstring>
+           </arg>
+           <arg type="s" name="account_id">
+               <tp:docstring>
+                   Account id related
+               </tp:docstring>
+           </arg>
+           <arg type="s" name="conversation_id">
+               <tp:docstring>
+                   Conversation id
+               </tp:docstring>
+           </arg>
+           <annotation name="org.qtproject.QtDBus.QtTypeName.Out3" value="VectorMapStringString"/>
+           <arg type="aa{ss}" name="messages">
+               <tp:docstring>
+                    Messages of the conversation
+               </tp:docstring>
+           </arg>
+       </signal>
+
+       <signal name="messageReceived" tp:name-for-bindings="messageReceived">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Notify clients when a conversation receives a new message
+           </tp:docstring>
+           <arg type="s" name="account_id">
+               <tp:docstring>
+                   Account id related
+               </tp:docstring>
+           </arg>
+           <arg type="s" name="conversation_id">
+               <tp:docstring>
+                   Conversation id
+               </tp:docstring>
+           </arg>
+           <annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="MapStringString"/>
+           <arg type="a{ss}" name="message">
+               <tp:docstring>
+                    The new message
+               </tp:docstring>
+           </arg>
+       </signal>
+
+       <signal name="conversationRequestReceived" tp:name-for-bindings="conversationRequestReceived">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Notify clients when a new conversation request is received
+           </tp:docstring>
+           <arg type="s" name="account_id">
+               <tp:docstring>
+                   Account id related
+               </tp:docstring>
+           </arg>
+           <arg type="s" name="conversation_id">
+               <tp:docstring>
+                   Conversation id
+               </tp:docstring>
+           </arg>
+           <annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="MapStringString"/>
+           <arg type="a{ss}" name="metadatas">
+               <tp:docstring>
+                    Informations of the request
+               </tp:docstring>
+           </arg>
+       </signal>
+
+       <signal name="conversationReady" tp:name-for-bindings="conversationReady">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Notify clients when a conversation is cloned and ready
+           </tp:docstring>
+           <arg type="s" name="account_id">
+               <tp:docstring>
+                   Account id related
+               </tp:docstring>
+           </arg>
+           <arg type="s" name="conversation_id">
+               <tp:docstring>
+                   Conversation id
+               </tp:docstring>
+           </arg>
+       </signal>
+
        <signal name="debugMessageReceived" tp:name-for-bindings="debugMessageReceived">
            <tp:added version="5.2.0"/>
            <tp:docstring>
diff --git a/bin/dbus/dbusclient.cpp b/bin/dbus/dbusclient.cpp
index e29badaae21da3f0cef88a252b93d9904e3a2c24..a33ee8a1ed9cfc57060323de670d3de50cbcb2fd 100644
--- a/bin/dbus/dbusclient.cpp
+++ b/bin/dbus/dbusclient.cpp
@@ -44,6 +44,7 @@
 #endif // ENABLE_PLUGIN
 
 #include "datatransfer_interface.h"
+#include "conversation_interface.h"
 
 #ifdef ENABLE_VIDEO
 #include "dbusvideomanager.h"
@@ -57,20 +58,17 @@
 
 static constexpr const char* const JAMI_DBUS_NAME = "cx.ring.Ring";
 
-class EventCallback :
-    public DBus::Callback_Base<void, DBus::DefaultTimeout&>
+class EventCallback : public DBus::Callback_Base<void, DBus::DefaultTimeout&>
 {
-    public:
-        EventCallback(const std::function<void()>&& func)
-            : callback_ {std::forward<const std::function<void()>>(func)}
-            {}
+public:
+    EventCallback(const std::function<void()>&& func)
+        : callback_ {std::forward<const std::function<void()>>(func)}
+    {}
 
-        void call(DBus::DefaultTimeout&) const {
-            callback_();
-        }
+    void call(DBus::DefaultTimeout&) const { callback_(); }
 
-    private:
-        const std::function<void()> callback_;
+private:
+    const std::function<void()> callback_;
 };
 
 DBusClient::DBusClient(int flags, bool persistent)
@@ -90,18 +88,20 @@ DBusClient::DBusClient(int flags, bool persistent)
         configurationManager_.reset(new DBusConfigurationManager {sessionConnection});
         presenceManager_.reset(new DBusPresenceManager {sessionConnection});
 #ifdef ENABLE_PLUGIN
-        pluginManagerInterface_.reset(new DBusPluginManagerInterface{sessionConnection});
+        pluginManagerInterface_.reset(new DBusPluginManagerInterface {sessionConnection});
 #endif
         DBusInstance::OnNoMoreClientFunc onNoMoreClientFunc;
         if (!persistent)
-            onNoMoreClientFunc = [this] {this->exit();};
+            onNoMoreClientFunc = [this] {
+                this->exit();
+            };
 
         instanceManager_.reset(new DBusInstance {sessionConnection, onNoMoreClientFunc});
 
 #ifdef ENABLE_VIDEO
         videoManager_.reset(new DBusVideoManager {sessionConnection});
 #endif
-    } catch (const DBus::Error &err) {
+    } catch (const DBus::Error& err) {
         throw std::runtime_error {"cannot initialize DBus stuff"};
     }
 
@@ -140,6 +140,7 @@ DBusClient::initLibrary(int flags)
     using DRing::PresenceSignal;
     using DRing::AudioSignal;
     using DRing::DataTransferSignal;
+    using DRing::ConversationSignal;
 
     using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>;
 
@@ -183,62 +184,112 @@ DBusClient::initLibrary(int flags)
 
     // Configuration event handlers
     const std::map<std::string, SharedCallback> configEvHandlers = {
-        exportable_callback<ConfigurationSignal::VolumeChanged>(bind(&DBusConfigurationManager::volumeChanged, confM, _1, _2)),
-        exportable_callback<ConfigurationSignal::AccountsChanged>(bind(&DBusConfigurationManager::accountsChanged, confM)),
-        exportable_callback<ConfigurationSignal::AccountDetailsChanged>(bind(&DBusConfigurationManager::accountDetailsChanged, confM, _1, _2)),
-        exportable_callback<ConfigurationSignal::StunStatusFailed>(bind(&DBusConfigurationManager::stunStatusFailure, confM, _1)),
-        exportable_callback<ConfigurationSignal::RegistrationStateChanged>(bind(&DBusConfigurationManager::registrationStateChanged, confM, _1, _2, _3, _4)),
-        exportable_callback<ConfigurationSignal::VolatileDetailsChanged>(bind(&DBusConfigurationManager::volatileAccountDetailsChanged, confM, _1, _2)),
-        exportable_callback<ConfigurationSignal::Error>(bind(&DBusConfigurationManager::errorAlert, confM, _1)),
-        exportable_callback<ConfigurationSignal::IncomingAccountMessage>(bind(&DBusConfigurationManager::incomingAccountMessage, confM, _1, _2, _3, _4 )),
-        exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(bind(&DBusConfigurationManager::accountMessageStatusChanged, confM, _1, _2, _3, _4 )),
-        exportable_callback<ConfigurationSignal::ProfileReceived>(bind(&DBusConfigurationManager::profileReceived, confM, _1, _2, _3 )),
-        exportable_callback<ConfigurationSignal::ComposingStatusChanged>(bind(&DBusConfigurationManager::composingStatusChanged, confM, _1, _2, _3 )),
-        exportable_callback<ConfigurationSignal::IncomingTrustRequest>(bind(&DBusConfigurationManager::incomingTrustRequest, confM, _1, _2, _3, _4 )),
-        exportable_callback<ConfigurationSignal::ContactAdded>(bind(&DBusConfigurationManager::contactAdded, confM, _1, _2, _3 )),
-        exportable_callback<ConfigurationSignal::ContactRemoved>(bind(&DBusConfigurationManager::contactRemoved, confM, _1, _2, _3 )),
-        exportable_callback<ConfigurationSignal::ExportOnRingEnded>(bind(&DBusConfigurationManager::exportOnRingEnded, confM, _1, _2, _3 )),
-        exportable_callback<ConfigurationSignal::KnownDevicesChanged>(bind(&DBusConfigurationManager::knownDevicesChanged, confM, _1, _2 )),
-        exportable_callback<ConfigurationSignal::NameRegistrationEnded>(bind(&DBusConfigurationManager::nameRegistrationEnded, confM, _1, _2, _3 )),
-        exportable_callback<ConfigurationSignal::UserSearchEnded>(bind(&DBusConfigurationManager::userSearchEnded, confM, _1, _2, _3, _4 )),
-        exportable_callback<ConfigurationSignal::RegisteredNameFound>(bind(&DBusConfigurationManager::registeredNameFound, confM, _1, _2, _3, _4 )),
-        exportable_callback<ConfigurationSignal::DeviceRevocationEnded>(bind(&DBusConfigurationManager::deviceRevocationEnded, confM, _1, _2, _3)),
-        exportable_callback<ConfigurationSignal::AccountProfileReceived>(bind(&DBusConfigurationManager::accountProfileReceived, confM, _1, _2, _3)),
-        exportable_callback<ConfigurationSignal::CertificatePinned>(bind(&DBusConfigurationManager::certificatePinned, confM, _1 )),
-        exportable_callback<ConfigurationSignal::CertificatePathPinned>(bind(&DBusConfigurationManager::certificatePathPinned, confM, _1, _2 )),
-        exportable_callback<ConfigurationSignal::CertificateExpired>(bind(&DBusConfigurationManager::certificateExpired, confM, _1 )),
-        exportable_callback<ConfigurationSignal::CertificateStateChanged>(bind(&DBusConfigurationManager::certificateStateChanged, confM, _1, _2, _3 )),
-        exportable_callback<ConfigurationSignal::MediaParametersChanged>(bind(&DBusConfigurationManager::mediaParametersChanged, confM, _1 )),
-        exportable_callback<ConfigurationSignal::MigrationEnded>(bind(&DBusConfigurationManager::migrationEnded, confM, _1, _2 )),
-        exportable_callback<ConfigurationSignal::HardwareDecodingChanged>(bind(&DBusConfigurationManager::hardwareDecodingChanged, confM, _1 )),
-        exportable_callback<ConfigurationSignal::HardwareEncodingChanged>(bind(&DBusConfigurationManager::hardwareEncodingChanged, confM, _1 )),
+        exportable_callback<ConfigurationSignal::VolumeChanged>(
+            bind(&DBusConfigurationManager::volumeChanged, confM, _1, _2)),
+        exportable_callback<ConfigurationSignal::AccountsChanged>(
+            bind(&DBusConfigurationManager::accountsChanged, confM)),
+        exportable_callback<ConfigurationSignal::AccountDetailsChanged>(
+            bind(&DBusConfigurationManager::accountDetailsChanged, confM, _1, _2)),
+        exportable_callback<ConfigurationSignal::StunStatusFailed>(
+            bind(&DBusConfigurationManager::stunStatusFailure, confM, _1)),
+        exportable_callback<ConfigurationSignal::RegistrationStateChanged>(
+            bind(&DBusConfigurationManager::registrationStateChanged, confM, _1, _2, _3, _4)),
+        exportable_callback<ConfigurationSignal::VolatileDetailsChanged>(
+            bind(&DBusConfigurationManager::volatileAccountDetailsChanged, confM, _1, _2)),
+        exportable_callback<ConfigurationSignal::Error>(
+            bind(&DBusConfigurationManager::errorAlert, confM, _1)),
+        exportable_callback<ConfigurationSignal::IncomingAccountMessage>(
+            bind(&DBusConfigurationManager::incomingAccountMessage, confM, _1, _2, _3, _4)),
+        exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(
+            bind(&DBusConfigurationManager::accountMessageStatusChanged, confM, _1, _2, _3, _4)),
+        exportable_callback<ConfigurationSignal::ProfileReceived>(
+            bind(&DBusConfigurationManager::profileReceived, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::ComposingStatusChanged>(
+            bind(&DBusConfigurationManager::composingStatusChanged, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::IncomingTrustRequest>(
+            bind(&DBusConfigurationManager::incomingTrustRequest, confM, _1, _2, _3, _4)),
+        exportable_callback<ConfigurationSignal::ContactAdded>(
+            bind(&DBusConfigurationManager::contactAdded, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::ContactRemoved>(
+            bind(&DBusConfigurationManager::contactRemoved, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::ExportOnRingEnded>(
+            bind(&DBusConfigurationManager::exportOnRingEnded, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::KnownDevicesChanged>(
+            bind(&DBusConfigurationManager::knownDevicesChanged, confM, _1, _2)),
+        exportable_callback<ConfigurationSignal::NameRegistrationEnded>(
+            bind(&DBusConfigurationManager::nameRegistrationEnded, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::UserSearchEnded>(
+            bind(&DBusConfigurationManager::userSearchEnded, confM, _1, _2, _3, _4)),
+        exportable_callback<ConfigurationSignal::RegisteredNameFound>(
+            bind(&DBusConfigurationManager::registeredNameFound, confM, _1, _2, _3, _4)),
+        exportable_callback<ConfigurationSignal::DeviceRevocationEnded>(
+            bind(&DBusConfigurationManager::deviceRevocationEnded, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::AccountProfileReceived>(
+            bind(&DBusConfigurationManager::accountProfileReceived, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::CertificatePinned>(
+            bind(&DBusConfigurationManager::certificatePinned, confM, _1)),
+        exportable_callback<ConfigurationSignal::CertificatePathPinned>(
+            bind(&DBusConfigurationManager::certificatePathPinned, confM, _1, _2)),
+        exportable_callback<ConfigurationSignal::CertificateExpired>(
+            bind(&DBusConfigurationManager::certificateExpired, confM, _1)),
+        exportable_callback<ConfigurationSignal::CertificateStateChanged>(
+            bind(&DBusConfigurationManager::certificateStateChanged, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::MediaParametersChanged>(
+            bind(&DBusConfigurationManager::mediaParametersChanged, confM, _1)),
+        exportable_callback<ConfigurationSignal::MigrationEnded>(
+            bind(&DBusConfigurationManager::migrationEnded, confM, _1, _2)),
+        exportable_callback<ConfigurationSignal::HardwareDecodingChanged>(
+            bind(&DBusConfigurationManager::hardwareDecodingChanged, confM, _1)),
+        exportable_callback<ConfigurationSignal::HardwareEncodingChanged>(
+            bind(&DBusConfigurationManager::hardwareEncodingChanged, confM, _1)),
     };
 
     // Presence event handlers
     const std::map<std::string, SharedCallback> presEvHandlers = {
-        exportable_callback<PresenceSignal::NewServerSubscriptionRequest>(bind(&DBusPresenceManager::newServerSubscriptionRequest, presM, _1)),
-        exportable_callback<PresenceSignal::ServerError>(bind(&DBusPresenceManager::serverError, presM, _1, _2, _3)),
-        exportable_callback<PresenceSignal::NewBuddyNotification>(bind(&DBusPresenceManager::newBuddyNotification, presM, _1, _2, _3, _4)),
-        exportable_callback<PresenceSignal::NearbyPeerNotification>(bind(&DBusPresenceManager::nearbyPeerNotification, presM, _1, _2, _3, _4)),
-        exportable_callback<PresenceSignal::SubscriptionStateChanged>(bind(&DBusPresenceManager::subscriptionStateChanged, presM, _1, _2, _3)),
+        exportable_callback<PresenceSignal::NewServerSubscriptionRequest>(
+            bind(&DBusPresenceManager::newServerSubscriptionRequest, presM, _1)),
+        exportable_callback<PresenceSignal::ServerError>(
+            bind(&DBusPresenceManager::serverError, presM, _1, _2, _3)),
+        exportable_callback<PresenceSignal::NewBuddyNotification>(
+            bind(&DBusPresenceManager::newBuddyNotification, presM, _1, _2, _3, _4)),
+        exportable_callback<PresenceSignal::NearbyPeerNotification>(
+            bind(&DBusPresenceManager::nearbyPeerNotification, presM, _1, _2, _3, _4)),
+        exportable_callback<PresenceSignal::SubscriptionStateChanged>(
+            bind(&DBusPresenceManager::subscriptionStateChanged, presM, _1, _2, _3)),
     };
 
     // Audio event handlers
     const std::map<std::string, SharedCallback> audioEvHandlers = {
-        exportable_callback<AudioSignal::DeviceEvent>(bind(&DBusConfigurationManager::audioDeviceEvent, confM)),
-        exportable_callback<AudioSignal::AudioMeter>(bind(&DBusConfigurationManager::audioMeter, confM, _1, _2)),
+        exportable_callback<AudioSignal::DeviceEvent>(
+            bind(&DBusConfigurationManager::audioDeviceEvent, confM)),
+        exportable_callback<AudioSignal::AudioMeter>(
+            bind(&DBusConfigurationManager::audioMeter, confM, _1, _2)),
     };
 
     const std::map<std::string, SharedCallback> dataXferEvHandlers = {
-        exportable_callback<DataTransferSignal::DataTransferEvent>(bind(&DBusConfigurationManager::dataTransferEvent, confM, _1, _2)),
+        exportable_callback<DataTransferSignal::DataTransferEvent>(
+            bind(&DBusConfigurationManager::dataTransferEvent, confM, _1, _2)),
+    };
+
+    const std::map<std::string, SharedCallback> convEvHandlers = {
+        exportable_callback<ConversationSignal::ConversationLoaded>(
+            bind(&DBusConfigurationManager::conversationLoaded, confM, _1, _2, _3, _4)),
+        exportable_callback<ConversationSignal::MessageReceived>(
+            bind(&DBusConfigurationManager::messageReceived, confM, _1, _2, _3)),
+        exportable_callback<ConversationSignal::ConversationRequestReceived>(
+            bind(&DBusConfigurationManager::conversationRequestReceived, confM, _1, _2, _3)),
+        exportable_callback<ConversationSignal::ConversationReady>(
+            bind(&DBusConfigurationManager::conversationReady, confM, _1, _2)),
     };
 
 #ifdef ENABLE_VIDEO
     // Video event handlers
     const std::map<std::string, SharedCallback> videoEvHandlers = {
         exportable_callback<VideoSignal::DeviceEvent>(bind(&DBusVideoManager::deviceEvent, videoM)),
-        exportable_callback<VideoSignal::DecodingStarted>(bind(&DBusVideoManager::startedDecoding, videoM, _1, _2, _3, _4, _5)),
-        exportable_callback<VideoSignal::DecodingStopped>(bind(&DBusVideoManager::stoppedDecoding, videoM, _1, _2, _3)),
+        exportable_callback<VideoSignal::DecodingStarted>(
+            bind(&DBusVideoManager::startedDecoding, videoM, _1, _2, _3, _4, _5)),
+        exportable_callback<VideoSignal::DecodingStopped>(
+            bind(&DBusVideoManager::stoppedDecoding, videoM, _1, _2, _3)),
     };
 #endif
 
@@ -250,6 +301,7 @@ DBusClient::initLibrary(int flags)
     DRing::registerSignalHandlers(presEvHandlers);
     DRing::registerSignalHandlers(audioEvHandlers);
     DRing::registerSignalHandlers(dataXferEvHandlers);
+    DRing::registerSignalHandlers(convEvHandlers);
 #ifdef ENABLE_VIDEO
     DRing::registerSignalHandlers(videoEvHandlers);
 #endif
diff --git a/bin/dbus/dbusconfigurationmanager.cpp b/bin/dbus/dbusconfigurationmanager.cpp
index 7e2ea1afb2132b2a8febd8debd905282b97fc0bc..c29d2ffe9cb5c6303cb69a3c27ea66991bb09a68 100644
--- a/bin/dbus/dbusconfigurationmanager.cpp
+++ b/bin/dbus/dbusconfigurationmanager.cpp
@@ -21,36 +21,40 @@
 #include "dbusconfigurationmanager.h"
 #include "configurationmanager_interface.h"
 #include "datatransfer_interface.h"
+#include "conversation_interface.h"
 
 DBusConfigurationManager::DBusConfigurationManager(DBus::Connection& connection)
     : DBus::ObjectAdaptor(connection, "/cx/ring/Ring/ConfigurationManager")
 {}
 
 auto
-DBusConfigurationManager::getAccountDetails(const std::string& accountID) -> decltype(DRing::getAccountDetails(accountID))
+DBusConfigurationManager::getAccountDetails(const std::string& accountID)
+    -> decltype(DRing::getAccountDetails(accountID))
 {
     return DRing::getAccountDetails(accountID);
 }
 
 auto
-DBusConfigurationManager::getVolatileAccountDetails(const std::string& accountID) -> decltype(DRing::getVolatileAccountDetails(accountID))
+DBusConfigurationManager::getVolatileAccountDetails(const std::string& accountID)
+    -> decltype(DRing::getVolatileAccountDetails(accountID))
 {
     return DRing::getVolatileAccountDetails(accountID);
 }
 
 void
-DBusConfigurationManager::setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details)
+DBusConfigurationManager::setAccountDetails(const std::string& accountID,
+                                            const std::map<std::string, std::string>& details)
 {
     DRing::setAccountDetails(accountID, details);
 }
 
 auto
-DBusConfigurationManager::testAccountICEInitialization(const std::string& accountID) -> decltype(DRing::testAccountICEInitialization(accountID))
+DBusConfigurationManager::testAccountICEInitialization(const std::string& accountID)
+    -> decltype(DRing::testAccountICEInitialization(accountID))
 {
     return DRing::testAccountICEInitialization(accountID);
 }
 
-
 void
 DBusConfigurationManager::setAccountActive(const std::string& accountID, const bool& active)
 {
@@ -58,67 +62,90 @@ DBusConfigurationManager::setAccountActive(const std::string& accountID, const b
 }
 
 auto
-DBusConfigurationManager::getAccountTemplate(const std::string& accountType) -> decltype(DRing::getAccountTemplate(accountType))
+DBusConfigurationManager::getAccountTemplate(const std::string& accountType)
+    -> decltype(DRing::getAccountTemplate(accountType))
 {
     return DRing::getAccountTemplate(accountType);
 }
 
 auto
-DBusConfigurationManager::addAccount(const std::map<std::string, std::string>& details) -> decltype(DRing::addAccount(details))
+DBusConfigurationManager::addAccount(const std::map<std::string, std::string>& details)
+    -> decltype(DRing::addAccount(details))
 {
     return DRing::addAccount(details);
 }
 
 auto
-DBusConfigurationManager::exportOnRing(const std::string& accountID, const std::string& password) -> decltype(DRing::exportOnRing(accountID, password))
+DBusConfigurationManager::exportOnRing(const std::string& accountID, const std::string& password)
+    -> decltype(DRing::exportOnRing(accountID, password))
 {
     return DRing::exportOnRing(accountID, password);
 }
 
 auto
-DBusConfigurationManager::exportToFile(const std::string& accountID, const std::string& destinationPath, const std::string& password) -> decltype(DRing::exportToFile(accountID, destinationPath, password))
+DBusConfigurationManager::exportToFile(const std::string& accountID,
+                                       const std::string& destinationPath,
+                                       const std::string& password)
+    -> decltype(DRing::exportToFile(accountID, destinationPath, password))
 {
     return DRing::exportToFile(accountID, destinationPath, password);
 }
 
 auto
-DBusConfigurationManager::revokeDevice(const std::string& accountID, const std::string& password, const std::string& device) -> decltype(DRing::revokeDevice(accountID, password, device))
+DBusConfigurationManager::revokeDevice(const std::string& accountID,
+                                       const std::string& password,
+                                       const std::string& device)
+    -> decltype(DRing::revokeDevice(accountID, password, device))
 {
     return DRing::revokeDevice(accountID, password, device);
 }
 
 auto
-DBusConfigurationManager::getKnownRingDevices(const std::string& accountID) -> decltype(DRing::getKnownRingDevices(accountID))
+DBusConfigurationManager::getKnownRingDevices(const std::string& accountID)
+    -> decltype(DRing::getKnownRingDevices(accountID))
 {
     return DRing::getKnownRingDevices(accountID);
 }
 
 auto
-DBusConfigurationManager::changeAccountPassword(const std::string& accountID, const std::string& password_old, const std::string& password_new) -> decltype(DRing::changeAccountPassword(accountID, password_old, password_new))
+DBusConfigurationManager::changeAccountPassword(const std::string& accountID,
+                                                const std::string& password_old,
+                                                const std::string& password_new)
+    -> decltype(DRing::changeAccountPassword(accountID, password_old, password_new))
 {
     return DRing::changeAccountPassword(accountID, password_old, password_new);
 }
 
 auto
-DBusConfigurationManager::lookupName(const std::string& account, const std::string& nameserver, const std::string& name) -> decltype(DRing::lookupName(account, nameserver, name))
+DBusConfigurationManager::lookupName(const std::string& account,
+                                     const std::string& nameserver,
+                                     const std::string& name)
+    -> decltype(DRing::lookupName(account, nameserver, name))
 {
     return DRing::lookupName(account, nameserver, name);
 }
 
 auto
-DBusConfigurationManager::lookupAddress(const std::string& account, const std::string& nameserver, const std::string& address) -> decltype(DRing::lookupAddress(account, nameserver, address))
+DBusConfigurationManager::lookupAddress(const std::string& account,
+                                        const std::string& nameserver,
+                                        const std::string& address)
+    -> decltype(DRing::lookupAddress(account, nameserver, address))
 {
     return DRing::lookupAddress(account, nameserver, address);
 }
 
 auto
-DBusConfigurationManager::registerName(const std::string& account, const std::string& password, const std::string& name) -> decltype(DRing::registerName(account, password, name))
+DBusConfigurationManager::registerName(const std::string& account,
+                                       const std::string& password,
+                                       const std::string& name)
+    -> decltype(DRing::registerName(account, password, name))
 {
     return DRing::registerName(account, password, name);
 }
 
 auto
-DBusConfigurationManager::searchUser(const std::string& account, const std::string& query) -> decltype(DRing::searchUser(account, query))
+DBusConfigurationManager::searchUser(const std::string& account, const std::string& query)
+    -> decltype(DRing::searchUser(account, query))
 {
     return DRing::searchUser(account, query);
 }
@@ -148,13 +175,17 @@ DBusConfigurationManager::registerAllAccounts(void)
 }
 
 auto
-DBusConfigurationManager::sendTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& payloads) -> decltype(DRing::sendAccountTextMessage(accountID, to, payloads))
+DBusConfigurationManager::sendTextMessage(const std::string& accountID,
+                                          const std::string& to,
+                                          const std::map<std::string, std::string>& payloads)
+    -> decltype(DRing::sendAccountTextMessage(accountID, to, payloads))
 {
     return DRing::sendAccountTextMessage(accountID, to, payloads);
 }
 
 std::vector<RingDBusMessage>
-DBusConfigurationManager::getLastMessages(const std::string& accountID, const uint64_t& base_timestamp)
+DBusConfigurationManager::getLastMessages(const std::string& accountID,
+                                          const uint64_t& base_timestamp)
 {
     auto messages = DRing::getLastMessages(accountID, base_timestamp);
     std::vector<RingDBusMessage> result;
@@ -175,13 +206,15 @@ DBusConfigurationManager::getNearbyPeers(const std::string& accountID)
 }
 
 auto
-DBusConfigurationManager::getMessageStatus(const uint64_t& id) -> decltype(DRing::getMessageStatus(id))
+DBusConfigurationManager::getMessageStatus(const uint64_t& id)
+    -> decltype(DRing::getMessageStatus(id))
 {
     return DRing::getMessageStatus(id);
 }
 
 auto
-DBusConfigurationManager::getMessageStatus(const std::string& accountID, const uint64_t& id) -> decltype(DRing::getMessageStatus(accountID, id))
+DBusConfigurationManager::getMessageStatus(const std::string& accountID, const uint64_t& id)
+    -> decltype(DRing::getMessageStatus(accountID, id))
 {
     return DRing::getMessageStatus(accountID, id);
 }
@@ -193,13 +226,18 @@ DBusConfigurationManager::cancelMessage(const std::string& accountID, const uint
 }
 
 void
-DBusConfigurationManager::setIsComposing(const std::string& accountID, const std::string& to, const bool& isWriting)
+DBusConfigurationManager::setIsComposing(const std::string& accountID,
+                                         const std::string& to,
+                                         const bool& isWriting)
 {
     DRing::setIsComposing(accountID, to, isWriting);
 }
 
 bool
-DBusConfigurationManager::setMessageDisplayed(const std::string& accountID, const std::string& contactId, const std::string& messageId, const int32_t& status)
+DBusConfigurationManager::setMessageDisplayed(const std::string& accountID,
+                                              const std::string& contactId,
+                                              const std::string& messageId,
+                                              const int32_t& status)
 {
     return DRing::setMessageDisplayed(accountID, contactId, messageId, status);
 }
@@ -217,32 +255,38 @@ DBusConfigurationManager::getSupportedTlsMethod() -> decltype(DRing::getSupporte
 }
 
 auto
-DBusConfigurationManager::getSupportedCiphers(const std::string& accountID) -> decltype(DRing::getSupportedCiphers(accountID))
+DBusConfigurationManager::getSupportedCiphers(const std::string& accountID)
+    -> decltype(DRing::getSupportedCiphers(accountID))
 {
     return DRing::getSupportedCiphers(accountID);
 }
 
 auto
-DBusConfigurationManager::getCodecDetails(const std::string& accountID, const unsigned& codecId) -> decltype(DRing::getCodecDetails(accountID, codecId))
+DBusConfigurationManager::getCodecDetails(const std::string& accountID, const unsigned& codecId)
+    -> decltype(DRing::getCodecDetails(accountID, codecId))
 {
     return DRing::getCodecDetails(accountID, codecId);
 }
 
 auto
-DBusConfigurationManager::setCodecDetails(const std::string& accountID, const unsigned& codecId, const std::map<std::string, std::string>& details)
--> decltype(DRing::setCodecDetails(accountID, codecId, details))
+DBusConfigurationManager::setCodecDetails(const std::string& accountID,
+                                          const unsigned& codecId,
+                                          const std::map<std::string, std::string>& details)
+    -> decltype(DRing::setCodecDetails(accountID, codecId, details))
 {
     return DRing::setCodecDetails(accountID, codecId, details);
 }
 
 auto
-DBusConfigurationManager::getActiveCodecList(const std::string& accountID) -> decltype(DRing::getActiveCodecList(accountID))
+DBusConfigurationManager::getActiveCodecList(const std::string& accountID)
+    -> decltype(DRing::getActiveCodecList(accountID))
 {
     return DRing::getActiveCodecList(accountID);
 }
 
 void
-DBusConfigurationManager::setActiveCodecList(const std::string& accountID, const std::vector<unsigned>& list)
+DBusConfigurationManager::setActiveCodecList(const std::string& accountID,
+                                             const std::vector<unsigned>& list)
 {
     DRing::setActiveCodecList(accountID, list);
 }
@@ -290,25 +334,29 @@ DBusConfigurationManager::getAudioInputDeviceList() -> decltype(DRing::getAudioI
 }
 
 auto
-DBusConfigurationManager::getCurrentAudioDevicesIndex() -> decltype(DRing::getCurrentAudioDevicesIndex())
+DBusConfigurationManager::getCurrentAudioDevicesIndex()
+    -> decltype(DRing::getCurrentAudioDevicesIndex())
 {
     return DRing::getCurrentAudioDevicesIndex();
 }
 
 auto
-DBusConfigurationManager::getAudioInputDeviceIndex(const std::string& name) -> decltype(DRing::getAudioInputDeviceIndex(name))
+DBusConfigurationManager::getAudioInputDeviceIndex(const std::string& name)
+    -> decltype(DRing::getAudioInputDeviceIndex(name))
 {
     return DRing::getAudioInputDeviceIndex(name);
 }
 
 auto
-DBusConfigurationManager::getAudioOutputDeviceIndex(const std::string& name) -> decltype(DRing::getAudioOutputDeviceIndex(name))
+DBusConfigurationManager::getAudioOutputDeviceIndex(const std::string& name)
+    -> decltype(DRing::getAudioOutputDeviceIndex(name))
 {
     return DRing::getAudioOutputDeviceIndex(name);
 }
 
 auto
-DBusConfigurationManager::getCurrentAudioOutputPlugin() -> decltype(DRing::getCurrentAudioOutputPlugin())
+DBusConfigurationManager::getCurrentAudioOutputPlugin()
+    -> decltype(DRing::getCurrentAudioOutputPlugin())
 {
     return DRing::getCurrentAudioOutputPlugin();
 }
@@ -392,13 +440,15 @@ DBusConfigurationManager::getAudioManager() -> decltype(DRing::getAudioManager()
 }
 
 auto
-DBusConfigurationManager::setAudioManager(const std::string& api) -> decltype(DRing::setAudioManager(api))
+DBusConfigurationManager::setAudioManager(const std::string& api)
+    -> decltype(DRing::setAudioManager(api))
 {
     return DRing::setAudioManager(api);
 }
 
 auto
-DBusConfigurationManager::getSupportedAudioManagers() -> decltype(DRing::getSupportedAudioManagers())
+DBusConfigurationManager::getSupportedAudioManagers()
+    -> decltype(DRing::getSupportedAudioManagers())
 {
     return DRing::getSupportedAudioManagers();
 }
@@ -484,23 +534,33 @@ DBusConfigurationManager::setAccountsOrder(const std::string& order)
 auto
 DBusConfigurationManager::validateCertificate(const std::string& accountId, const std::string& certificate) -> decltype(DRing::validateCertificate(accountId, certificate))
 {
-   return DRing::validateCertificate(accountId, certificate);
+    return DRing::validateCertificate(accountId, certificate);
 }
 
 auto
-DBusConfigurationManager::validateCertificatePath(const std::string& accountId, const std::string& certificate, const std::string& privateKey, const std::string& privateKeyPass, const std::string& caList) -> decltype(DRing::validateCertificatePath(accountId, certificate, privateKey, privateKeyPass, caList))
+DBusConfigurationManager::validateCertificatePath(const std::string& accountId,
+                                                  const std::string& certificate,
+                                                  const std::string& privateKey,
+                                                  const std::string& privateKeyPass,
+                                                  const std::string& caList)
+    -> decltype(
+        DRing::validateCertificatePath(accountId, certificate, privateKey, privateKeyPass, caList))
 {
-   return DRing::validateCertificatePath(accountId, certificate, privateKey, privateKeyPass, caList);
+    return DRing::validateCertificatePath(accountId, certificate, privateKey, privateKeyPass, caList);
 }
 
 auto
-DBusConfigurationManager::getCertificateDetails(const std::string& certificate) -> decltype(DRing::getCertificateDetails(certificate))
+DBusConfigurationManager::getCertificateDetails(const std::string& certificate)
+    -> decltype(DRing::getCertificateDetails(certificate))
 {
     return DRing::getCertificateDetails(certificate);
 }
 
 auto
-DBusConfigurationManager::getCertificateDetailsPath(const std::string& certificate, const std::string& privateKey, const std::string& privateKeyPass) -> decltype(DRing::getCertificateDetailsPath(certificate, privateKey, privateKeyPass))
+DBusConfigurationManager::getCertificateDetailsPath(const std::string& certificate,
+                                                    const std::string& privateKey,
+                                                    const std::string& privateKeyPass)
+    -> decltype(DRing::getCertificateDetailsPath(certificate, privateKey, privateKeyPass))
 {
     return DRing::getCertificateDetailsPath(certificate, privateKey, privateKeyPass);
 }
@@ -512,7 +572,8 @@ DBusConfigurationManager::getPinnedCertificates() -> decltype(DRing::getPinnedCe
 }
 
 auto
-DBusConfigurationManager::pinCertificate(const std::vector<uint8_t>& certificate, const bool& local) -> decltype(DRing::pinCertificate(certificate, local))
+DBusConfigurationManager::pinCertificate(const std::vector<uint8_t>& certificate, const bool& local)
+    -> decltype(DRing::pinCertificate(certificate, local))
 {
     return DRing::pinCertificate(certificate, local);
 }
@@ -524,55 +585,69 @@ DBusConfigurationManager::pinCertificatePath(const std::string& certPath)
 }
 
 auto
-DBusConfigurationManager::unpinCertificate(const std::string& certId) -> decltype(DRing::unpinCertificate(certId))
+DBusConfigurationManager::unpinCertificate(const std::string& certId)
+    -> decltype(DRing::unpinCertificate(certId))
 {
     return DRing::unpinCertificate(certId);
 }
 
 auto
-DBusConfigurationManager::unpinCertificatePath(const std::string& p) -> decltype(DRing::unpinCertificatePath(p))
+DBusConfigurationManager::unpinCertificatePath(const std::string& p)
+    -> decltype(DRing::unpinCertificatePath(p))
 {
     return DRing::unpinCertificatePath(p);
 }
 
 auto
-DBusConfigurationManager::pinRemoteCertificate(const std::string& accountId, const std::string& certId) -> decltype(DRing::pinRemoteCertificate(accountId, certId))
+DBusConfigurationManager::pinRemoteCertificate(const std::string& accountId,
+                                               const std::string& certId)
+    -> decltype(DRing::pinRemoteCertificate(accountId, certId))
 {
     return DRing::pinRemoteCertificate(accountId, certId);
 }
 
 auto
-DBusConfigurationManager::setCertificateStatus(const std::string& accountId, const std::string& certId, const std::string& status) -> decltype(DRing::setCertificateStatus(accountId, certId, status))
+DBusConfigurationManager::setCertificateStatus(const std::string& accountId,
+                                               const std::string& certId,
+                                               const std::string& status)
+    -> decltype(DRing::setCertificateStatus(accountId, certId, status))
 {
     return DRing::setCertificateStatus(accountId, certId, status);
 }
 
 auto
-DBusConfigurationManager::getCertificatesByStatus(const std::string& accountId, const std::string& status) -> decltype(DRing::getCertificatesByStatus(accountId, status))
+DBusConfigurationManager::getCertificatesByStatus(const std::string& accountId,
+                                                  const std::string& status)
+    -> decltype(DRing::getCertificatesByStatus(accountId, status))
 {
     return DRing::getCertificatesByStatus(accountId, status);
 }
 
 auto
-DBusConfigurationManager::getTrustRequests(const std::string& accountId) -> decltype(DRing::getTrustRequests(accountId))
+DBusConfigurationManager::getTrustRequests(const std::string& accountId)
+    -> decltype(DRing::getTrustRequests(accountId))
 {
     return DRing::getTrustRequests(accountId);
 }
 
 auto
-DBusConfigurationManager::acceptTrustRequest(const std::string& accountId, const std::string& from) -> decltype(DRing::acceptTrustRequest(accountId, from))
+DBusConfigurationManager::acceptTrustRequest(const std::string& accountId, const std::string& from)
+    -> decltype(DRing::acceptTrustRequest(accountId, from))
 {
     return DRing::acceptTrustRequest(accountId, from);
 }
 
 auto
-DBusConfigurationManager::discardTrustRequest(const std::string& accountId, const std::string& from) -> decltype(DRing::discardTrustRequest(accountId, from))
+DBusConfigurationManager::discardTrustRequest(const std::string& accountId, const std::string& from)
+    -> decltype(DRing::discardTrustRequest(accountId, from))
 {
     return DRing::discardTrustRequest(accountId, from);
 }
 
 void
-DBusConfigurationManager::sendTrustRequest(const std::string& accountId, const std::string& to, const std::vector<uint8_t>& payload)
+DBusConfigurationManager::sendTrustRequest(const std::string& accountId,
+                                           const std::string& to,
+                                           const std::vector<uint8_t>& payload)
 {
     DRing::sendTrustRequest(accountId, to, payload);
 }
@@ -584,37 +659,44 @@ DBusConfigurationManager::addContact(const std::string& accountId, const std::st
 }
 
 void
-DBusConfigurationManager::removeContact(const std::string& accountId, const std::string& uri, const bool& ban)
+DBusConfigurationManager::removeContact(const std::string& accountId,
+                                        const std::string& uri,
+                                        const bool& ban)
 {
     DRing::removeContact(accountId, uri, ban);
 }
 
 auto
-DBusConfigurationManager::getContactDetails(const std::string& accountId, const std::string& uri) -> decltype(DRing::getContactDetails(accountId, uri))
+DBusConfigurationManager::getContactDetails(const std::string& accountId, const std::string& uri)
+    -> decltype(DRing::getContactDetails(accountId, uri))
 {
     return DRing::getContactDetails(accountId, uri);
 }
 
 auto
-DBusConfigurationManager::getContacts(const std::string& accountId) -> decltype(DRing::getContacts(accountId))
+DBusConfigurationManager::getContacts(const std::string& accountId)
+    -> decltype(DRing::getContacts(accountId))
 {
     return DRing::getContacts(accountId);
 }
 
 auto
-DBusConfigurationManager::getCredentials(const std::string& accountID) -> decltype(DRing::getCredentials(accountID))
+DBusConfigurationManager::getCredentials(const std::string& accountID)
+    -> decltype(DRing::getCredentials(accountID))
 {
     return DRing::getCredentials(accountID);
 }
 
 void
-DBusConfigurationManager::setCredentials(const std::string& accountID, const std::vector<std::map<std::string, std::string>>& details)
+DBusConfigurationManager::setCredentials(
+    const std::string& accountID, const std::vector<std::map<std::string, std::string>>& details)
 {
     DRing::setCredentials(accountID, details);
 }
 
 auto
-DBusConfigurationManager::getAddrFromInterfaceName(const std::string& interface) -> decltype(DRing::getAddrFromInterfaceName(interface))
+DBusConfigurationManager::getAddrFromInterfaceName(const std::string& interface)
+    -> decltype(DRing::getAddrFromInterfaceName(interface))
 {
     return DRing::getAddrFromInterfaceName(interface);
 }
@@ -638,7 +720,7 @@ DBusConfigurationManager::getShortcuts() -> decltype(DRing::getShortcuts())
 }
 
 void
-DBusConfigurationManager::setShortcuts(const std::map<std::string, std::string> &shortcutsMap)
+DBusConfigurationManager::setShortcuts(const std::map<std::string, std::string>& shortcutsMap)
 {
     DRing::setShortcuts(shortcutsMap);
 }
@@ -656,13 +738,17 @@ DBusConfigurationManager::getVolume(const std::string& device) -> decltype(DRing
 }
 
 auto
-DBusConfigurationManager::exportAccounts(const std::vector<std::string>& accountIDs, const std::string& filepath, const std::string& password) -> decltype(DRing::exportAccounts(accountIDs, filepath, password))
+DBusConfigurationManager::exportAccounts(const std::vector<std::string>& accountIDs,
+                                         const std::string& filepath,
+                                         const std::string& password)
+    -> decltype(DRing::exportAccounts(accountIDs, filepath, password))
 {
     return DRing::exportAccounts(accountIDs, filepath, password);
 }
 
 auto
-DBusConfigurationManager::importAccounts(const std::string& archivePath, const std::string& password) -> decltype(DRing::importAccounts(archivePath, password))
+DBusConfigurationManager::importAccounts(const std::string& archivePath, const std::string& password)
+    -> decltype(DRing::importAccounts(archivePath, password))
 {
     return DRing::importAccounts(archivePath, password);
 }
@@ -719,14 +805,17 @@ DBusConfigurationManager::dataTransferInfo(const DRing::DataTransferId& id,
 }
 
 void
-DBusConfigurationManager::dataTransferBytesProgress(const uint64_t& id, uint32_t& error,
-                                                    int64_t& total, int64_t& progress)
+DBusConfigurationManager::dataTransferBytesProgress(const uint64_t& id,
+                                                    uint32_t& error,
+                                                    int64_t& total,
+                                                    int64_t& progress)
 {
     error = uint32_t(DRing::dataTransferBytesProgress(id, total, progress));
 }
 
 uint32_t
-DBusConfigurationManager::acceptFileTransfer(const uint64_t& id, const std::string& file_path,
+DBusConfigurationManager::acceptFileTransfer(const uint64_t& id,
+                                             const std::string& file_path,
                                              const int64_t& offset)
 {
     return uint32_t(DRing::acceptFileTransfer(id, file_path, offset));
@@ -738,6 +827,86 @@ DBusConfigurationManager::cancelDataTransfer(const uint64_t& id)
     return uint32_t(DRing::cancelDataTransfer(id));
 }
 
+std::string
+DBusConfigurationManager::startConversation(const std::string& accountId)
+{
+    return DRing::startConversation(accountId);
+}
+
+void
+DBusConfigurationManager::acceptConversationRequest(const std::string& accountId,
+                                                    const std::string& conversationId)
+{
+    DRing::acceptConversationRequest(accountId, conversationId);
+}
+
+void
+DBusConfigurationManager::declineConversationRequest(const std::string& accountId,
+                                                     const std::string& conversationId)
+{
+    DRing::declineConversationRequest(accountId, conversationId);
+}
+
+bool
+DBusConfigurationManager::removeConversation(const std::string& accountId,
+                                             const std::string& conversationId)
+{
+    return DRing::removeConversation(accountId, conversationId);
+}
+
+std::vector<std::string>
+DBusConfigurationManager::getConversations(const std::string& accountId)
+{
+    return DRing::getConversations(accountId);
+}
+
+std::vector<std::map<std::string, std::string>>
+DBusConfigurationManager::getConversationRequests(const std::string& accountId)
+{
+    return DRing::getConversationRequests(accountId);
+}
+
+bool
+DBusConfigurationManager::addConversationMember(const std::string& accountId,
+                                                const std::string& conversationId,
+                                                const std::string& contactUri)
+{
+    return DRing::addConversationMember(accountId, conversationId, contactUri);
+}
+
+bool
+DBusConfigurationManager::removeConversationMember(const std::string& accountId,
+                                                   const std::string& conversationId,
+                                                   const std::string& contactUri)
+{
+    return DRing::removeConversationMember(accountId, conversationId, contactUri);
+}
+
+std::vector<std::map<std::string, std::string>>
+DBusConfigurationManager::getConversationMembers(const std::string& accountId,
+                                                 const std::string& conversationId)
+{
+    return DRing::getConversationMembers(accountId, conversationId);
+}
+
+void
+DBusConfigurationManager::sendMessage(const std::string& accountId,
+                                      const std::string& conversationId,
+                                      const std::string& message,
+                                      const std::string& parent)
+{
+    DRing::sendMessage(accountId, conversationId, message, parent);
+}
+
+uint32_t
+DBusConfigurationManager::loadConversationMessages(const std::string& accountId,
+                                                   const std::string& conversationId,
+                                                   const std::string& fromMessage,
+                                                   const uint32_t& n)
+{
+    return DRing::loadConversationMessages(accountId, conversationId, fromMessage, n);
+}
+
 bool
 DBusConfigurationManager::isAudioMeterActive(const std::string& id)
 {
diff --git a/bin/dbus/dbusconfigurationmanager.h b/bin/dbus/dbusconfigurationmanager.h
index 956b28b2f48e0d4b6a04e20bbace69dbca1c3db8..1400b6b7c3dcf03a321e687ccdbdb9a45d265f69 100644
--- a/bin/dbus/dbusconfigurationmanager.h
+++ b/bin/dbus/dbusconfigurationmanager.h
@@ -34,7 +34,7 @@
 
 #include "dring/datatransfer_interface.h"
 
-#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6)
+#if __GNUC__ >= 5 || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
 /* This warning option only exists for gcc 4.6.0 and greater. */
 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #endif
@@ -45,22 +45,29 @@
 #pragma GCC diagnostic warning "-Wignored-qualifiers"
 #pragma GCC diagnostic warning "-Wunused-parameter"
 
-#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6)
+#if __GNUC__ >= 5 || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
 /* This warning option only exists for gcc 4.6.0 and greater. */
 #pragma GCC diagnostic warning "-Wunused-but-set-variable"
 #endif
 
 using RingDBusMessage = DBus::Struct<std::string, std::map<std::string, std::string>, uint64_t>;
 
-class DRING_PUBLIC DBusConfigurationManager :
-    public cx::ring::Ring::ConfigurationManager_adaptor,
-    public DBus::IntrospectableAdaptor,
-    public DBus::ObjectAdaptor
+class DRING_PUBLIC DBusConfigurationManager : public cx::ring::Ring::ConfigurationManager_adaptor,
+                                              public DBus::IntrospectableAdaptor,
+                                              public DBus::ObjectAdaptor
 {
-    public:
-        using RingDBusDataTransferInfo = DBus::Struct<std::string, uint32_t, uint32_t, int64_t, int64_t, std::string, std::string, std::string, std::string>;
+public:
+    using RingDBusDataTransferInfo = DBus::Struct<std::string,
+                                                  uint32_t,
+                                                  uint32_t,
+                                                  int64_t,
+                                                  int64_t,
+                                                  std::string,
+                                                  std::string,
+                                                  std::string,
+                                                  std::string>;
 
-        DBusConfigurationManager(DBus::Connection& connection);
+    DBusConfigurationManager(DBus::Connection& connection);
 
         // Methods
         std::map<std::string, std::string> getAccountDetails(const std::string& accountID);
@@ -183,6 +190,28 @@ class DRING_PUBLIC DBusConfigurationManager :
         bool isLocalModeratorsEnabled(const std::string& accountID);
         void setAllModerators(const std::string& accountID, const bool& allModerators);
         bool isAllModerators(const std::string& accountID);
+        std::string startConversation(const std::string& accountId);
+        void acceptConversationRequest(const std::string& accountId, const std::string& conversationId);
+        void declineConversationRequest(const std::string& accountId, const std::string& conversationId);
+        bool removeConversation(const std::string& accountId, const std::string& conversationId);
+        std::vector<std::string> getConversations(const std::string& accountId);
+        std::vector<std::map<std::string, std::string>> getConversationRequests(const std::string& accountId);
+        bool addConversationMember(const std::string& accountId,
+                                const std::string& conversationId,
+                                const std::string& contactUri);
+        bool removeConversationMember(const std::string& accountId,
+                                    const std::string& conversationId,
+                                    const std::string& contactUri);
+        std::vector<std::map<std::string, std::string>> getConversationMembers(
+            const std::string& accountId, const std::string& conversationId);
+        void sendMessage(const std::string& accountId,
+                        const std::string& conversationId,
+                        const std::string& message,
+                        const std::string& parent);
+        uint32_t loadConversationMessages(const std::string& accountId,
+                                    const std::string& conversationId,
+                                    const std::string& fromMessage,
+                                    const uint32_t& n);
 };
 
 #endif // __RING_DBUSCONFIGURATIONMANAGER_H__
diff --git a/bin/jni/conversation.i b/bin/jni/conversation.i
new file mode 100644
index 0000000000000000000000000000000000000000..3abc9cb32a1c7aa3be98996b306a243dc9da6380
--- /dev/null
+++ b/bin/jni/conversation.i
@@ -0,0 +1,65 @@
+/*
+ *  Copyright (C) 2004-2021 Savoir-faire Linux Inc.
+ *
+ *  Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+%header %{
+#include "dring/dring.h"
+#include "dring/conversation_interface.h"
+
+class ConversationCallback {
+public:
+    virtual ~ConversationCallback(){}
+    virtual void conversationLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){}
+    virtual void messageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/){}
+    virtual void conversationRequestReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*metadatas*/){}
+    virtual void conversationReady(const std::string& /*accountId*/, const std::string& /* conversationId */){}
+};
+%}
+
+%feature("director") ConversationCallback;
+
+namespace DRing {
+
+  // Conversation management
+  std::string startConversation(const std::string& accountId);
+  void acceptConversationRequest(const std::string& accountId, const std::string& conversationId);
+  void declineConversationRequest(const std::string& accountId, const std::string& conversationId);
+  bool removeConversation(const std::string& accountId, const std::string& conversationId);
+  std::vector<std::string> getConversations(const std::string& accountId);
+  std::vector<std::map<std::string, std::string>> getConversationRequests(const std::string& accountId);
+
+  // Member management
+  bool addConversationMember(const std::string& accountId, const std::string& conversationId, const std::string& contactUri);
+  bool removeConversationMember(const std::string& accountId, const std::string& conversationId, const std::string& contactUri);
+  std::vector<std::map<std::string, std::string>> getConversationMembers(const std::string& accountId, const std::string& conversationId);
+
+  // Message send/load
+  void sendMessage(const std::string& accountId, const std::string& conversationId, const std::string& message, const std::string& parent);
+  uint32_t loadConversationMessages(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, size_t n);
+
+}
+
+class ConversationCallback {
+public:
+    virtual ~ConversationCallback(){}
+    virtual void conversationLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){}
+    virtual void messageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/){}
+    virtual void conversationRequestReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*metadatas*/){}
+    virtual void conversationReady(const std::string& /*accountId*/, const std::string& /* conversationId */){}
+};
\ No newline at end of file
diff --git a/bin/jni/jni_interface.i b/bin/jni/jni_interface.i
index 1e6977e993329c3f315f0c25b36c96ac673934eb..9d57ad8528d9e60cb75559e447162972377fd331 100644
--- a/bin/jni/jni_interface.i
+++ b/bin/jni/jni_interface.i
@@ -209,6 +209,7 @@ namespace std {
 %include "presencemanager.i"
 %include "videomanager.i"
 %include "plugin_manager_interface.i"
+%include "conversation.i"
 
 #include "dring/callmanager_interface.h"
 
@@ -217,7 +218,7 @@ namespace std {
  * that are not declared elsewhere in the c++ code
  */
 
-void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM, DataTransferCallback* dataM, VideoCallback* videoM) {
+void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM, DataTransferCallback* dataM, VideoCallback* videoM, ConversationCallback* convM) {
     using namespace std::placeholders;
 
     using std::bind;
@@ -228,6 +229,7 @@ void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM
     using DRing::DataTransferSignal;
     using DRing::PresenceSignal;
     using DRing::VideoSignal;
+    using DRing::ConversationSignal;
 
     using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>;
 
@@ -310,6 +312,13 @@ void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM
         exportable_callback<VideoSignal::DecodingStopped>(bind(&VideoCallback::decodingStopped, videoM, _1, _2, _3)),
     };
 
+    const std::map<std::string, SharedCallback> conversationHandlers = {
+        exportable_callback<ConversationSignal::ConversationLoaded>(bind(&ConversationCallback::conversationLoaded, convM, _1, _2, _3, _4)),
+        exportable_callback<ConversationSignal::MessageReceived>(bind(&ConversationCallback::messageReceived, convM, _1, _2, _3)),
+        exportable_callback<ConversationSignal::ConversationRequestReceived>(bind(&ConversationCallback::conversationRequestReceived, convM, _1, _2, _3)),
+        exportable_callback<ConversationSignal::ConversationReady>(bind(&ConversationCallback::conversationReady, convM, _1, _2))
+    };
+
     if (!DRing::init(static_cast<DRing::InitFlag>(DRing::DRING_FLAG_DEBUG)))
         return;
 
@@ -318,6 +327,7 @@ void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM
     registerSignalHandlers(presenceEvHandlers);
     registerSignalHandlers(dataTransferEvHandlers);
     registerSignalHandlers(videoEvHandlers);
+    registerSignalHandlers(conversationHandlers);
 
     DRing::start();
 }
diff --git a/bin/nodejs/conversation.i b/bin/nodejs/conversation.i
new file mode 100644
index 0000000000000000000000000000000000000000..b246337d5fc0b5c49333c7f8c19e590de9323f64
--- /dev/null
+++ b/bin/nodejs/conversation.i
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (C) 2004-2021 Savoir-faire Linux Inc.
+ *
+ *  Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+%header %{
+#include "dring/dring.h"
+#include "dring/conversation_interface.h"
+
+class ConversationCallback {
+public:
+    virtual ~ConversationCallback(){}
+    virtual void conversationLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){}
+    virtual void messageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/){}
+    virtual void conversationRequestReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*metadatas*/){}
+    virtual void conversationReady(const std::string& /*accountId*/, const std::string& /* conversationId */){}
+};
+%}
+
+%feature("director") ConversationCallback;
+
+namespace DRing {
+
+  struct DataTransferInfo
+  {
+    std::string accountId;
+    DRing::DataTransferEventCode lastEvent;
+    uint32_t flags;
+    int64_t totalSize;
+    int64_t bytesProgress;
+    std::string peer;
+    std::string displayName;
+    std::string path;
+    std::string mimetype;
+  };
+
+  // Conversation management
+  std::string startConversation(const std::string& accountId);
+  void acceptConversationRequest(const std::string& accountId, const std::string& conversationId);
+  void declineConversationRequest(const std::string& accountId, const std::string& conversationId);
+  bool removeConversation(const std::string& accountId, const std::string& conversationId);
+  std::vector<std::string> getConversations(const std::string& accountId);
+  std::vector<std::map<std::string, std::string>> getConversationRequests(const std::string& accountId);
+
+  // Member management
+  bool addConversationMember(const std::string& accountId, const std::string& conversationId, const std::string& contactUri);
+  bool removeConversationMember(const std::string& accountId, const std::string& conversationId, const std::string& contactUri);
+  std::vector<std::map<std::string, std::string>> getConversationMembers(const std::string& accountId, const std::string& conversationId);
+
+  // Message send/load
+  void sendMessage(const std::string& accountId, const std::string& conversationId, const std::string& message, const std::string& parent);
+  uint32_t loadConversationMessages(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, size_t n);
+
+}
+
+class ConversationCallback {
+public:
+    virtual ~ConversationCallback(){}
+    virtual void conversationLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){}
+    virtual void messageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/){}
+    virtual void conversationRequestReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*metadatas*/){}
+    virtual void conversationReady(const std::string& /*accountId*/, const std::string& /* conversationId */){}
+};
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
index 10416660944ef2550f164ace47a9cf3fc2b12c6e..30c89fe66a6dcff308cd29eb595bc41f04203e90 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl Jami - configure.ac
 
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ([2.69])
-AC_INIT([Jami Daemon],[9.10.0],[jami@gnu.org],[jami])
+AC_INIT([Jami Daemon],[10.0.0],[jami@gnu.org],[jami])
 
 AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2021]])
 AC_REVISION([$Revision$])
diff --git a/src/client/conversation_interface.cpp b/src/client/conversation_interface.cpp
index 75475ca86889c636662e4add749a84a6a892c2fe..4f0c3cf98de0280977cce44ca5e3320e43b08f48 100644
--- a/src/client/conversation_interface.cpp
+++ b/src/client/conversation_interface.cpp
@@ -120,14 +120,15 @@ sendMessage(const std::string& accountId,
         acc->sendMessage(conversationId, message, parent);
 }
 
-void
+uint32_t
 loadConversationMessages(const std::string& accountId,
                          const std::string& conversationId,
                          const std::string& fromMessage,
                          size_t n)
 {
     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
-        acc->loadConversationMessages(conversationId, fromMessage, n);
+        return acc->loadConversationMessages(conversationId, fromMessage, n);
+    return 0;
 }
 
 } // namespace DRing
diff --git a/src/dring/conversation_interface.h b/src/dring/conversation_interface.h
index 890fdf3ac91b918587fdb689aaac072d018015f0..ac450fbf664e807a513bfffee788ddcfbf2822d7 100644
--- a/src/dring/conversation_interface.h
+++ b/src/dring/conversation_interface.h
@@ -58,7 +58,7 @@ DRING_PUBLIC void sendMessage(const std::string& accountId,
                               const std::string& conversationId,
                               const std::string& message,
                               const std::string& parent);
-DRING_PUBLIC void loadConversationMessages(const std::string& accountId,
+DRING_PUBLIC uint32_t loadConversationMessages(const std::string& accountId,
                                            const std::string& conversationId,
                                            const std::string& fromMessage,
                                            size_t n);
@@ -68,7 +68,8 @@ struct DRING_PUBLIC ConversationSignal
     struct DRING_PUBLIC ConversationLoaded
     {
         constexpr static const char* name = "ConversationLoaded";
-        using cb_type = void(const std::string& /*accountId*/,
+        using cb_type = void(uint32_t /* id */,
+                             const std::string& /*accountId*/,
                              const std::string& /* conversationId */,
                              std::vector<std::map<std::string, std::string>> /*messages*/);
     };
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index a25c8906ebe6ef6da7a8c783b21bc18b8a4f9c36..a1b681a223e9674a63cccefb3447b100015c20e1 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -238,6 +238,7 @@ constexpr const char* const JamiAccount::ACCOUNT_TYPE;
 constexpr const std::pair<uint16_t, uint16_t> JamiAccount::DHT_PORT_RANGE {4000, 8888};
 
 using ValueIdDist = std::uniform_int_distribution<dht::Value::Id>;
+using LoadIdDist = std::uniform_int_distribution<uint32_t>;
 
 static std::string_view
 stripPrefix(std::string_view toUrl)
@@ -326,6 +327,14 @@ JamiAccount::JamiAccount(const std::string& accountID, bool /* presenceEnabled *
     }
 
     setActiveCodecs({});
+
+    JAMI_INFO("Start loading conversations…");
+    auto conversationsRepositories = fileutils::readDirectory(idPath_ + DIR_SEPARATOR_STR
+                                                              + "conversations");
+    for (const auto& repository : conversationsRepositories) {
+        conversations_.emplace(repository, std::make_unique<Conversation>(weak(), repository));
+    }
+    JAMI_INFO("Conversations loaded!");
 }
 
 JamiAccount::~JamiAccount()
@@ -3336,8 +3345,7 @@ JamiAccount::sendTextMessage(const std::string& to,
                 return;
             }
             // TODO do not use getAccountDetails(), accountInfo
-            if (dev.toString()
-                == getAccountDetails()[DRing::Account::ConfProperties::RING_DEVICE_ID]) {
+            if (dev.toString() == currentDeviceId()) {
                 return;
             }
 
@@ -3666,7 +3674,8 @@ JamiAccount::startConversation()
 
     // TODO
     // And send an invite to others devices to sync the conversation between device
-    // Via getMemebers
+    // Via getMembers
+    emitSignal<DRing::ConversationSignal::ConversationReady>(accountID_, convId);
     return convId;
 }
 
@@ -3784,13 +3793,19 @@ JamiAccount::removeConversation(const std::string& conversationId)
 std::vector<std::string>
 JamiAccount::getConversations()
 {
-    return {}; // TODO
+    std::vector<std::string> result;
+    result.reserve(conversations_.size());
+    for (const auto& [key, _] : conversations_) {
+        result.emplace_back(key);
+    }
+    return result;
 }
 
 std::vector<std::map<std::string, std::string>>
-getConversationRequests()
+JamiAccount::getConversationRequests()
 {
-    return {}; // TODO
+    // TODO
+    return {};
 }
 
 // Member management
@@ -3858,7 +3873,7 @@ JamiAccount::sendMessage(const std::string& conversationId,
             Json::Value message;
             message["id"] = conversationId;
             message["commit"] = commitId;
-            message["deviceId"] = getAccountDetails()[DRing::Account::ConfProperties::RING_DEVICE_ID];
+            message["deviceId"] = std::string(currentDeviceId());
             Json::StreamWriterBuilder builder;
             const auto text = Json::writeString(builder, message);
             for (const auto& members : conversation->second->getMembers()) {
@@ -3874,22 +3889,27 @@ JamiAccount::sendMessage(const std::string& conversationId,
     }
 }
 
-void
+uint32_t
 JamiAccount::loadConversationMessages(const std::string& conversationId,
                                       const std::string& fromMessage,
                                       size_t n)
 {
+    if (conversations_.find(conversationId) == conversations_.end())
+        return 0;
+    const uint32_t id = LoadIdDist()(rand);
     // loadMessages will perform a git log that can take quite some time, so to avoid any lock, run
     // it the threadpool
-    dht::ThreadPool::io().run([this, conversationId, fromMessage, n] {
+    dht::ThreadPool::io().run([this, conversationId, fromMessage, n, id] {
         auto conversation = conversations_.find(conversationId);
         if (conversation != conversations_.end() && conversation->second) {
             auto messages = conversation->second->loadMessages(fromMessage, n);
-            emitSignal<DRing::ConversationSignal::ConversationLoaded>(accountID_,
+            emitSignal<DRing::ConversationSignal::ConversationLoaded>(id,
+                                                                      accountID_,
                                                                       conversationId,
                                                                       messages);
         }
     });
+    return id;
 }
 
 void
diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h
index 579cda575f08a0b5027f5541e1f34333bfed419b..3aa22f78a5a85b7de71a950dd8d264b95f56e22d 100644
--- a/src/jamidht/jamiaccount.h
+++ b/src/jamidht/jamiaccount.h
@@ -515,7 +515,7 @@ public:
                      const std::string& message,
                      const std::string& parent = "",
                      const std::string& type = "text/plain");
-    void loadConversationMessages(const std::string& conversationId,
+    uint32_t loadConversationMessages(const std::string& conversationId,
                                   const std::string& fromMessage = "",
                                   size_t n = 0);
 
diff --git a/test/unitTest/conversation/conversation.cpp b/test/unitTest/conversation/conversation.cpp
index b0c7e1758cdd3da17085565001d53cf323e70e2c..6326cd5acfed0260fb392b79271b3fe462b11771 100644
--- a/test/unitTest/conversation/conversation.cpp
+++ b/test/unitTest/conversation/conversation.cpp
@@ -144,12 +144,27 @@ void
 ConversationTest::testCreateConversation()
 {
     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
-    auto aliceDeviceId = aliceAccount
-                             ->getAccountDetails()[DRing::Account::ConfProperties::RING_DEVICE_ID];
-    auto uri = aliceAccount->getAccountDetails()[DRing::Account::ConfProperties::USERNAME];
-    if (uri.find("ring:") == 0)
-        uri = uri.substr(std::string("ring:").size());
+    auto aliceDeviceId = aliceAccount->currentDeviceId();
+    auto uri = aliceAccount->getUsername();
+
+    std::mutex mtx;
+    std::unique_lock<std::mutex> lk {mtx};
+    std::condition_variable cv;
+    std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> confHandlers;
+    bool conversationReady = false;
+    confHandlers.insert(DRing::exportable_callback<DRing::ConversationSignal::ConversationReady>(
+        [&](const std::string& accountId, const std::string& /* conversationId */) {
+            if (accountId == aliceId) {
+                conversationReady = true;
+                cv.notify_one();
+            }
+        }));
+    DRing::registerSignalHandlers(confHandlers);
+
+    // Start conversation
     auto convId = aliceAccount->startConversation();
+    cv.wait_for(lk, std::chrono::seconds(30), [&]() { return conversationReady; });
+    CPPUNIT_ASSERT(conversationReady);
 
     // Assert that repository exists
     auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + aliceAccount->getAccountID()
@@ -177,11 +192,8 @@ void
 ConversationTest::testGetConversation()
 {
     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
-    auto aliceDeviceId = aliceAccount
-                             ->getAccountDetails()[DRing::Account::ConfProperties::RING_DEVICE_ID];
-    auto uri = aliceAccount->getAccountDetails()[DRing::Account::ConfProperties::USERNAME];
-    if (uri.find("ring:") == 0)
-        uri = uri.substr(std::string("ring:").size());
+    auto aliceDeviceId = aliceAccount->currentDeviceId();
+    auto uri = aliceAccount->getUsername();
     auto convId = aliceAccount->startConversation();
 
     auto conversations = aliceAccount->getConversations();
@@ -194,9 +206,7 @@ ConversationTest::testAddMember()
 {
     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
-    auto bobUri = bobAccount->getAccountDetails()[ConfProperties::USERNAME];
-    if (bobUri.find("ring:") == 0)
-        bobUri = bobUri.substr(std::string("ring:").size());
+    auto bobUri = bobAccount->getUsername();
     auto convId = aliceAccount->startConversation();
     std::mutex mtx;
     std::unique_lock<std::mutex> lk {mtx};
@@ -253,12 +263,8 @@ ConversationTest::testGetMembers()
 {
     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
-    auto bobUri = bobAccount->getAccountDetails()[ConfProperties::USERNAME];
-    auto aliceUri = aliceAccount->getAccountDetails()[ConfProperties::USERNAME];
-    if (bobUri.find("ring:") == 0)
-        bobUri = bobUri.substr(std::string("ring:").size());
-    if (aliceUri.find("ring:") == 0)
-        aliceUri = aliceUri.substr(std::string("ring:").size());
+    auto bobUri = bobAccount->getUsername();
+    auto aliceUri = aliceAccount->getUsername();
     std::mutex mtx;
     std::unique_lock<std::mutex> lk {mtx};
     std::condition_variable cv;
@@ -303,9 +309,7 @@ ConversationTest::testGetMembers()
 
     auto members = aliceAccount->getConversationMembers(convId);
     CPPUNIT_ASSERT(members.size() == 1);
-    CPPUNIT_ASSERT(members[0]["uri"]
-                   == aliceAccount->getAccountDetails()[ConfProperties::USERNAME].substr(
-                       std::string("ring:").size()));
+    CPPUNIT_ASSERT(members[0]["uri"] == aliceAccount->getUsername());
     CPPUNIT_ASSERT(members[0]["role"] == "admin");
 
     cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; });
@@ -327,9 +331,7 @@ ConversationTest::testSendMessage()
 {
     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
-    auto bobUri = bobAccount->getAccountDetails()[ConfProperties::USERNAME];
-    if (bobUri.find("ring:") == 0)
-        bobUri = bobUri.substr(std::string("ring:").size());
+    auto bobUri = bobAccount->getUsername();
 
     std::mutex mtx;
     std::unique_lock<std::mutex> lk {mtx};
@@ -358,9 +360,11 @@ ConversationTest::testSendMessage()
                 cv.notify_one();
             }));
     confHandlers.insert(DRing::exportable_callback<DRing::ConversationSignal::ConversationReady>(
-        [&](const std::string& /*accountId*/, const std::string& /* conversationId */) {
-            conversationReady = true;
-            cv.notify_one();
+        [&](const std::string& accountId, const std::string& /* conversationId */) {
+            if (accountId == bobId) {
+                conversationReady = true;
+                cv.notify_one();
+            }
         }));
     DRing::registerSignalHandlers(confHandlers);