diff --git a/src/api/conversationmodel.h b/src/api/conversationmodel.h
index 82c0faa7ff1de5fdb60366045fa6e30103c587a8..a30a141bc4f38b2f4f997da318d96aca01fd6869 100644
--- a/src/api/conversationmodel.h
+++ b/src/api/conversationmodel.h
@@ -148,9 +148,11 @@ public:
      */
     void deleteObsoleteHistory(int date);
 
-    void sendFile(const std::string& uid, const std::string& path, const std::string& filename);
+    void sendFile(const std::string& convUid, const std::string& path, const std::string& filename);
 
-    void acceptFile(const std::string& uid, uint64_t interactionId);
+    void acceptTransfer(const std::string& convUid, uint64_t interactionId, const std::string& path);
+
+    void cancelTransfer(const std::string& convUid, uint64_t interactionId);
 
 Q_SIGNALS:
     /**
diff --git a/src/api/datatransfer.h b/src/api/datatransfer.h
index 1de9fe7fe7b2bb9532e9eaadc31b9efc1b3be25f..8e9209f2a464d5478fd7bf7c51883d01431dc4be 100644
--- a/src/api/datatransfer.h
+++ b/src/api/datatransfer.h
@@ -17,6 +17,9 @@
  ***************************************************************************/
 #pragma once
 
+// std
+#include <ctime>
+
 // LRC
 #include "typedefs.h"
 
@@ -33,11 +36,62 @@ enum class Status {
     unjoinable_peer, // error: (outgoing only) peer connection failed
     invalid_pathname, // error: (file transfer only) given file is not a valid
     unsupported, // error: unable to do the transfer (generic error)
+    INVALID
 };
 
+static inline const std::string
+to_string(const Status& status)
+{
+    switch(status) {
+    case Status::on_connection:
+        return "on_connection";
+    case Status::on_progress:
+        return "on_progress";
+    case Status::success:
+        return "success";
+    case Status::stop_by_peer:
+        return "stop_by_peer";
+    case Status::stop_by_host:
+        return "stop_by_host";
+    case Status::unjoinable_peer:
+        return "unjoinable_peer";
+    case Status::invalid_pathname:
+        return "invalid_pathname";
+    case Status::unsupported:
+        return "unsupported";
+    case Status::INVALID:
+    default:
+        return "INVALID";
+    }
+}
+
+static inline Status
+to_status(const std::string& status)
+{
+    if (status == "on_connection")
+        return datatransfer::Status::on_connection;
+    else if (status == "on_progress")
+        return datatransfer::Status::on_progress;
+    else if (status == "success")
+        return datatransfer::Status::success;
+    else if (status == "stop_by_peer")
+        return datatransfer::Status::stop_by_peer;
+    else if (status == "stop_by_host")
+        return datatransfer::Status::stop_by_host;
+    else if (status == "unjoinable_peer")
+        return datatransfer::Status::unjoinable_peer;
+    else if (status == "invalid_pathname")
+        return datatransfer::Status::invalid_pathname;
+    else if (status == "unsupported")
+        return datatransfer::Status::unsupported;
+    else
+        return datatransfer::Status::INVALID;
+
+}
+
 struct Info
 {
-    std::string uid; ///< long-term and unique identifier (used for historic)
+    const std::string uid; ///< long-term and unique identifier (used for historic)
     Status status;
     bool isOutgoing;
     std::size_t totalSize;
@@ -46,6 +100,7 @@ struct Info
     std::string displayName;
     std::string accountId;
     std::string peerUri;
+    std::time_t timestamp = 0;
 };
 
 } // namespace lrc::api::datatransfer
diff --git a/src/api/datatransfermodel.h b/src/api/datatransfermodel.h
index de0edb858245e08f2629f87e7e373bc89f770d55..fc171a969dca5813d2d0613c56ea2339eae546d0 100644
--- a/src/api/datatransfermodel.h
+++ b/src/api/datatransfermodel.h
@@ -41,6 +41,10 @@ namespace api {
 
 class BehaviorController;
 
+namespace datatransfer {
+class Info;
+} // namespace datatransfer
+
 /**
  *  @brief Class that manages data transfer.
  */
@@ -52,32 +56,26 @@ public:
                       const CallbacksHandler& callbacksHandler);
     ~DataTransferModel();
 
-    std::vector<std::string> transferIdList() const;
-
-    std::string sendFile(const std::string& account_id, const std::string& peer_uri,
+    void sendFile(const std::string& account_id, const std::string& peer_uri,
                          const std::string& file_path, const std::string& display_name);
 
     datatransfer::Info transferInfo(const std::string& uid);
 
-    std::streamsize bytesProgress(const std::string& id);
+    std::streamsize bytesProgress(int interactionId);
+
+    void accept(int interactionId, const std::string& file_path, std::size_t offset);
 
-    void acceptFile(const std::string& id, const std::string& file_path, std::size_t offset);
+    void cancel(int interactionId);
 
-    void cancel(const std::string& id);
+    void registerTransferId(long long dringId, int interactionId);
+
+    int getInteractionIdFromDringId(long long dringId);
 
 Q_SIGNALS:
     /**
      * Connect this signal to know when a data transfer is incoming.
-     * \note the unique identification is generated by the libring and its unicity scope is limited
-     * to the libring process life.
-     *
-     * @param transfer_id unique identification of incoming data transfer.
-     * @param display_name a free identification string given by sender.
-     * @oaram size total number of bytes of the transfer (including offset).
-     * @oaram offset offset of first given bytes for continued transfer.
      */
-    void incomingTransfer(const std::string& uid, const std::string& display_name,
-                          const std::size_t size, const std::size_t offset);
+    void incomingTransfer(api::datatransfer::Info dataTransferInfo);
 
     /**
      * Connect this signal to know when an existing data transfer has changed of status.
diff --git a/src/api/interaction.h b/src/api/interaction.h
index 71f50705ae78c19b34f6738f1562c290bda2eded..f0871b4c41e6fd39de7da363d2978466a4b85514 100644
--- a/src/api/interaction.h
+++ b/src/api/interaction.h
@@ -35,7 +35,9 @@ enum class Type {
     INVALID,
     TEXT,
     CALL,
-    CONTACT
+    CONTACT,
+    OUTGOING_DATA_TRANSFER,
+    INCOMING_DATA_TRANSFER
 };
 
 static inline const std::string
@@ -48,6 +50,10 @@ to_string(const Type& type)
         return "CALL";
     case Type::CONTACT:
         return "CONTACT";
+    case Type::OUTGOING_DATA_TRANSFER:
+        return "OUTGOING_DATA_TRANSFER";
+    case Type::INCOMING_DATA_TRANSFER:
+        return "INCOMING_DATA_TRANSFER";
     case Type::INVALID:
     default:
         return "INVALID";
@@ -63,6 +69,10 @@ to_type(const std::string& type)
         return interaction::Type::CALL;
     else if (type == "CONTACT")
         return interaction::Type::CONTACT;
+    else if (type == "OUTGOING_DATA_TRANSFER")
+        return interaction::Type::OUTGOING_DATA_TRANSFER;
+    else if (type == "INCOMING_DATA_TRANSFER")
+        return interaction::Type::INCOMING_DATA_TRANSFER;
     else
         return interaction::Type::INVALID;
 }
@@ -75,7 +85,14 @@ enum class Status {
     FAILED,
     SUCCEED,
     READ,
-    UNREAD
+    UNREAD,
+    TRANSFER_CREATED, /*[jn] mettre à jour les fonctions de conversion */
+    TRANSFER_ACCEPTED,
+    TRANSFER_CANCELED,
+    TRANSFER_ERROR,
+    TRANSFER_ONGOING,
+    TRANSFER_AWAITING,
+    TRANSFER_FINISHED
 };
 
 static inline const std::string
@@ -94,7 +111,20 @@ to_string(const Status& status)
         return "READ";
     case Status::UNREAD:
         return "UNREAD";
-    case Status::INVALID:
+    case Status::TRANSFER_CREATED:
+        return "TRANSFER_CREATED";
+    case Status::TRANSFER_ACCEPTED:
+        return "TRANSFER_ACCEPTED";
+    case Status::TRANSFER_CANCELED:
+        return "TRANSFER_CANCELED";
+    case Status::TRANSFER_ERROR:
+        return "TRANSFER_ERROR";
+    case Status::TRANSFER_ONGOING:
+        return "TRANSFER_ONGOING";
+    case Status::TRANSFER_AWAITING:
+        return "TRANSFER_AWAITING";
+    case Status::TRANSFER_FINISHED:
+        return "TRANSFER_FINISHED";
     default:
         return "INVALID";
     }
@@ -115,6 +145,20 @@ to_status(const std::string& status)
         return interaction::Status::READ;
     else if (status == "UNREAD")
         return interaction::Status::UNREAD;
+    else if (status == "TRANSFER_CREATED")
+        return interaction::Status::TRANSFER_CREATED;
+    else if (status == "TRANSFER_ACCEPTED")
+        return interaction::Status::TRANSFER_ACCEPTED;
+    else if (status == "TRANSFER_CANCELED")
+        return interaction::Status::TRANSFER_CANCELED;
+    else if (status == "TRANSFER_ERROR")
+        return interaction::Status::TRANSFER_ERROR;
+    else if (status == "TRANSFER_ONGOING")
+        return interaction::Status::TRANSFER_ONGOING;
+    else if (status == "TRANSFER_AWAITING")
+        return interaction::Status::TRANSFER_AWAITING;
+    else if (status == "TRANSFER_FINISHED")
+        return interaction::Status::TRANSFER_FINISHED;
     else
         return interaction::Status::INVALID;
 
@@ -130,8 +174,9 @@ struct Info
 };
 
 static inline bool isOutgoing(const Info& interaction) {
-    return interaction.status != lrc::api::interaction::Status::READ
-    && interaction.status != lrc::api::interaction::Status::UNREAD;
+    return (interaction.status != lrc::api::interaction::Status::READ
+    && interaction.status != lrc::api::interaction::Status::UNREAD)
+    || interaction.type == lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER;
 }
 
 } // namespace interaction
diff --git a/src/authority/databasehelper.cpp b/src/authority/databasehelper.cpp
index 2a2b19337c4851f051ef79c2e603f68cd8b7e440..67b3343af123136cc90fef0666e91a846dbf2f21 100644
--- a/src/authority/databasehelper.cpp
+++ b/src/authority/databasehelper.cpp
@@ -18,6 +18,7 @@
  ***************************************************************************/
 #include "databasehelper.h"
 #include "api/profile.h"
+#include "api/datatransfer.h"
 
 namespace lrc
 {
@@ -209,6 +210,27 @@ addMessageToConversation(Database& db,
                           {":status", to_string(msg.status)}});
 }
 
+int
+addDataTransferToConversation(Database& db,
+                              const std::string& accountProfileId,
+                              const std::string& conversationId,
+                              const DataTransferInfo& infoFromDaemon)
+{
+    auto peerProfileId = getProfileId(db, infoFromDaemon.peer.toStdString());
+    auto authorId = (infoFromDaemon.isOutgoing) ? peerProfileId : peerProfileId;
+
+    return db.insertInto("interactions",
+                         {{":account_id", "account_id"}, {":author_id", "author_id"},
+                         {":conversation_id", "conversation_id"}, {":timestamp", "timestamp"},
+                         {":body", "body"}, {":type", "type"},
+                         {":status", "status"}},
+                         {{":account_id", accountProfileId}, {":author_id", authorId},
+                         {":conversation_id", conversationId},
+                         {":timestamp", std::to_string(std::time(nullptr))},
+                         {":body", infoFromDaemon.displayName.toStdString()}, {":type", (infoFromDaemon.isOutgoing)?"OUTGOING_DATA_TRANSFER":"INCOMING_DATA_TRANSFER"},
+                         {":status", "TRANSFER_CREATED"}});
+}
+
 int
 addOrUpdateMessage(Database& db,
                          const std::string& accountProfile,
@@ -267,7 +289,7 @@ std::string getInteractionIdByDaemonId(Database& db, const std::string& id)
 
 
 void updateInteractionStatus(Database& db, unsigned int id,
-                             api::interaction::Status& newStatus)
+                             api::interaction::Status newStatus)
 {
     db.update("interactions", "status=:status",
               {{":status", api::interaction::to_string(newStatus)}},
diff --git a/src/authority/databasehelper.h b/src/authority/databasehelper.h
index f4bcbe69855f6d20a51614b8a7019380da8a1f03..9ee85493c39ca7fd391384d51f8f709dcb0e03fc 100644
--- a/src/authority/databasehelper.h
+++ b/src/authority/databasehelper.h
@@ -177,7 +177,7 @@ std::string getInteractionIdByDaemonId(Database& db, const std::string& id);
  * @param newStatus
  */
 void updateInteractionStatus(Database& db, unsigned int id,
-                             api::interaction::Status& newStatus);
+                             api::interaction::Status newStatus);
 
 /**
  * Clear history but not the conversation started interaction
@@ -229,6 +229,10 @@ void addContact(Database& db, const std::string& accountUri, const std::string&
  */
 int countUnreadFromInteractions(Database& db, const std::string& conversationId);
 
+int addDataTransferToConversation(Database& db,
+                                  const std::string& accountProfileId,
+                                  const std::string& conversationId,
+                                  const DataTransferInfo& infoFromDaemon);
 } // namespace database
 
 } // namespace authority
diff --git a/src/callbackshandler.cpp b/src/callbackshandler.cpp
index 7781cf279044abfd23c4b323a7fff6678b2dbdba..f2e5fa92f6deec46c830b0512edda436db61f5d4 100644
--- a/src/callbackshandler.cpp
+++ b/src/callbackshandler.cpp
@@ -282,9 +282,34 @@ CallbacksHandler::slotAccountMessageStatusChanged(const QString& accountId,
 }
 
 void
-CallbacksHandler::slotDataTransferEvent(qulonglong dring_id, uint code)
+CallbacksHandler::slotDataTransferEvent(qulonglong dringId, uint codeStatus)
 {
-    emit incomingTransfer(-1, -1);
+    auto event = DRing::DataTransferEventCode(codeStatus);
+
+    switch (event) {
+    case DRing::DataTransferEventCode::created:
+        emit incomingTransfer(static_cast<long long>(dringId));
+        break;
+    case DRing::DataTransferEventCode::closed_by_host:
+    case DRing::DataTransferEventCode::closed_by_peer:
+        emit transferStatusCanceled(static_cast<long long>(dringId));
+        break;
+    case DRing::DataTransferEventCode::wait_peer_acceptance:
+    case DRing::DataTransferEventCode::wait_host_acceptance:
+        emit transferStatusAwaiting(static_cast<long long>(dringId));
+        break;
+    case DRing::DataTransferEventCode::ongoing:
+        emit transferStatusOngoing(static_cast<long long>(dringId));
+        break;
+    case DRing::DataTransferEventCode::finished:
+        emit transferStatusFinished(static_cast<long long>(dringId));
+        break;
+    case DRing::DataTransferEventCode::invalid_pathname:
+    case DRing::DataTransferEventCode::unjoinable_peer:
+    case DRing::DataTransferEventCode::unsupported:
+        emit transferStatusError(static_cast<long long>(dringId));
+        break;
+    }
 }
 
 } // namespace lrc
diff --git a/src/callbackshandler.h b/src/callbackshandler.h
index a1e4a65dfb5e6d6a466dc2a34c95cb2c72b363ba..adf4d2bdd2687bbc0c6d393d3e10f54c68188aa5 100644
--- a/src/callbackshandler.h
+++ b/src/callbackshandler.h
@@ -160,7 +160,13 @@ Q_SIGNALS:
                                      const uint64_t id,
                                      const std::string& to, int status);
 
-    void incomingTransfer(long long dring_id, uint code);
+    void incomingTransfer(long long dringId);
+    //~ void transferStatusChanged(const long long dringId, uint codeStatus);
+    void transferStatusCanceled(long long dringId);
+    void transferStatusAwaiting(long long dringId);
+    void transferStatusOngoing(long long dringId);
+    void transferStatusFinished(long long dringId);
+    void transferStatusError(long long dringId);
 
 private Q_SLOTS:
     /**
diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp
index 9dd7ce5b47cc42118a02b9adda2997ca22f24cd2..5ac5ea654258998891d93f43c507cf6757bfc219 100644
--- a/src/conversationmodel.cpp
+++ b/src/conversationmodel.cpp
@@ -214,13 +214,16 @@ public Q_SLOTS:
      */
     void slotConferenceRemoved(const std::string& confId);
 
-    void slotIncomingTransfer(const std::string& uid,
-                              const std::string& display_name,
-                              const std::size_t size,
-                              const std::size_t offset);
+    void slotIncomingTransfer(long long dringId);
 
-    void slotTransferStatusChanged(const std::string& uid,
-                               datatransfer::Status status);
+    //~ void slotTransferStatusChanged(long long dringId, uint codeStatus);
+
+    void slotCancelTransfer(long long dringId);
+
+    void slotTransferStatusAwaiting(long long dringId);
+    void slotTransferStatusOngoing(long long dringId);
+    void slotTransferStatusFinished(long long dringId);
+    void slotTransferStatusError(long long dringId);
 
 };
 
@@ -712,16 +715,31 @@ ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked,
             this,
             &ConversationModelPimpl::slotConferenceRemoved);
 
-    connect(&dataTransferModel,
-            &DataTransferModel::incomingTransfer,
+    // data transfer
+    connect(&callbacksHandler,
+            &CallbacksHandler::incomingTransfer,
             this,
             &ConversationModelPimpl::slotIncomingTransfer);
-
-    connect(&dataTransferModel,
-            &DataTransferModel::transferStatusChanged,
+    connect(&callbacksHandler,
+            &CallbacksHandler::transferStatusCanceled,
             this,
-            &ConversationModelPimpl::slotTransferStatusChanged);
-
+            &ConversationModelPimpl::slotCancelTransfer);
+    connect(&callbacksHandler,
+            &CallbacksHandler::transferStatusAwaiting,
+            this,
+            &ConversationModelPimpl::slotTransferStatusAwaiting);
+    connect(&callbacksHandler,
+            &CallbacksHandler::transferStatusOngoing,
+            this,
+            &ConversationModelPimpl::slotTransferStatusOngoing);
+    connect(&callbacksHandler,
+            &CallbacksHandler::transferStatusFinished,
+            this,
+            &ConversationModelPimpl::slotTransferStatusFinished);
+    connect(&callbacksHandler,
+            &CallbacksHandler::transferStatusError,
+            this,
+            &ConversationModelPimpl::slotTransferStatusError);
 }
 
 ConversationModelPimpl::~ConversationModelPimpl()
@@ -948,6 +966,14 @@ ConversationModelPimpl::addConversationWith(const std::string& convId,
             }
             slotUpdateInteractionStatus(linked.owner.id, std::stoull(id),
                                         contactUri, status);
+        } else if (interaction.second.status == interaction::Status::TRANSFER_CREATED
+                   || interaction.second.status == interaction::Status::TRANSFER_AWAITING
+                   || interaction.second.status == interaction::Status::TRANSFER_ONGOING
+                   || interaction.second.status == interaction::Status::TRANSFER_ACCEPTED) {
+            // If a datatransfer was left in a non-terminal status in DB, we switch this status to ERROR
+            // TODO : Improve for DBus clients as daemon and transfer may still be ongoing
+            database::updateInteractionStatus(db, interaction.first, interaction::Status::TRANSFER_ERROR);
+            interaction.second.status = interaction::Status::TRANSFER_ERROR;
         }
     }
 
@@ -1226,18 +1252,80 @@ ConversationModelPimpl::getNumberOfUnreadMessagesFor(const std::string& uid)
 }
 
 void
-ConversationModelPimpl::slotIncomingTransfer(const std::string& uid,
-                                             const std::string& display_name,
-                                             const std::size_t size,
-                                             const std::size_t offset)
+ConversationModelPimpl::slotIncomingTransfer(long long dringId)
 {
-    emit linked.newInteraction("", -1, {});
+    // no auto
+    DataTransferInfo infoFromDaemon = ConfigurationManager::instance().dataTransferInfo(dringId);
+
+    auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
+    auto contactProfileId = database::getProfileId(db, infoFromDaemon.peer.toStdString());
+
+    // get the conversation if any
+    auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
+
+    if (conv.empty())
+        return;
+
+    // add interaction to the db
+    auto interactionId = database::addDataTransferToConversation(db, accountProfileId, conv[0], infoFromDaemon);
+
+    // add transfert to the transfer model
+    dataTransferModel.registerTransferId(dringId, interactionId);
+
+    // prepare interaction Info and emit signal for the client
+    auto conversationIdx = indexOf(conv[0]);
+    if (conversationIdx != -1) {
+        auto& interactions = conversations[conversationIdx].interactions;
+        auto it = interactions.find(interactionId);
+
+        if (it != interactions.end()) {
+            return;
+        }
+
+        auto interaction = interaction::Info {contactProfileId, infoFromDaemon.displayName.toStdString(),
+                                              std::time(nullptr),
+                                              (infoFromDaemon.isOutgoing)?interaction::Type::OUTGOING_DATA_TRANSFER:interaction::Type::INCOMING_DATA_TRANSFER,
+                                              interaction::Status::TRANSFER_CREATED};
+
+        auto it2 = conversations[conversationIdx].interactions.emplace(interactionId, interaction);
+        conversations[conversationIdx].lastMessageUid = interactionId;
+        dirtyConversations = true;
+        emit linked.newInteraction(conv[0], interactionId, interaction);
+        sortConversations();
+        emit linked.modelSorted();
+    }
 }
 
 void
-ConversationModelPimpl::slotTransferStatusChanged(const std::string& uid, datatransfer::Status status)
+ConversationModelPimpl::slotCancelTransfer(long long dringId)
 {
-    emit linked.interactionStatusUpdated("", -1, {});
+    // no auto [jn] facto le code
+    DataTransferInfo infoFromDaemon = ConfigurationManager::instance().dataTransferInfo(dringId);
+
+    auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
+    auto contactProfileId = database::getProfileId(db, infoFromDaemon.peer.toStdString());
+
+    // get the conversation if any
+    auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
+
+    if (conv.empty())
+        return;
+
+    // get interaction id from data transfer model
+    auto interactionId = dataTransferModel.getInteractionIdFromDringId(dringId);
+
+    // update information in the db
+    database::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_CANCELED);
+
+    // prepare interaction Info and emit signal for the client
+    auto conversationIdx = indexOf(conv[0]);
+    if (conversationIdx != -1) {
+        auto& interactions = conversations[conversationIdx].interactions;
+        auto it = interactions.find(interactionId);
+        if (it != interactions.end()) {
+            emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
+        }
+    }
 }
 
 void
@@ -1246,19 +1334,188 @@ ConversationModel::sendFile(const std::string& uid, const std::string& path, con
     auto conversationIdx = pimpl_->indexOf(uid);
     if (conversationIdx != -1) {
         auto& peerUri = pimpl_->conversations[conversationIdx].participants.front();
-        if (not peerUri.empty())
+        if (not peerUri.empty()) {
             pimpl_->dataTransferModel.sendFile(owner.id.c_str(), peerUri.c_str(), path.c_str(), filename.c_str());
+        }
     }
 }
 
 void
-ConversationModel::acceptFile(const std::string& uid, uint64_t interactionId)
+ConversationModel::acceptTransfer(const std::string& convUid, uint64_t interactionId, const std::string& path)
 {
-    auto conversationIdx = pimpl_->indexOf(uid);
+    pimpl_->dataTransferModel.accept(interactionId, path, 0);
+    database::updateInteractionStatus(pimpl_->db, interactionId, interaction::Status::TRANSFER_ACCEPTED);
+
+    // prepare interaction Info and emit signal for the client
+    auto conversationIdx = pimpl_->indexOf(convUid);
+    if (conversationIdx != -1) {
+        auto& interactions = pimpl_->conversations[conversationIdx].interactions;
+        auto it = interactions.find(interactionId);
+        if (it != interactions.end()) {
+            it->second.status = interaction::Status::TRANSFER_ACCEPTED;
+            pimpl_->dirtyConversations = true;
+            emit interactionStatusUpdated(convUid, interactionId, it->second);
+        }
+    }
+}
+
+void
+ConversationModel::cancelTransfer(const std::string& convUid, uint64_t interactionId)
+{
+    // For this action, we change interaction status before effective canceling as daemon will
+    // emit Finished event code immediatly (before leaving this method) in non-DBus mode.
+    auto conversationIdx = pimpl_->indexOf(convUid);
+    if (conversationIdx != -1) {
+        auto& interactions = pimpl_->conversations[conversationIdx].interactions;
+        auto it = interactions.find(interactionId);
+        if (it != interactions.end()) {
+            it->second.status = interaction::Status::TRANSFER_CANCELED;
+
+            // update information in the db
+            database::updateInteractionStatus(pimpl_->db, interactionId, interaction::Status::TRANSFER_CANCELED);
+
+            // Forward cancel action to daemon
+            pimpl_->dataTransferModel.cancel(interactionId);
+            pimpl_->dirtyConversations = true;
+            emit interactionStatusUpdated(convUid, interactionId, it->second);
+        }
+    }
+}
+
+void
+ConversationModelPimpl::slotTransferStatusAwaiting(long long dringId)
+{
+    // no auto [jn] facto le code
+    DataTransferInfo infoFromDaemon = ConfigurationManager::instance().dataTransferInfo(dringId);
+
+    auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
+    auto contactProfileId = database::getProfileId(db, infoFromDaemon.peer.toStdString());
+
+    // get the conversation if any
+    auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
+
+    if (conv.empty())
+        return;
+
+    // get interaction id from data transfer model
+    auto interactionId = dataTransferModel.getInteractionIdFromDringId(dringId);
+
+    // update information in the db
+    database::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_AWAITING);
+
+    // prepare interaction Info and emit signal for the client
+    auto conversationIdx = indexOf(conv[0]);
+    if (conversationIdx != -1) {
+        auto& interactions = conversations[conversationIdx].interactions;
+        auto it = interactions.find(interactionId);
+        if (it != interactions.end()) {
+            it->second.status = interaction::Status::TRANSFER_AWAITING;
+            dirtyConversations = true;
+            emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
+        }
+    }
+}
+
+void
+ConversationModelPimpl::slotTransferStatusOngoing(long long dringId)
+{
+    // no auto [jn] facto le code
+    DataTransferInfo infoFromDaemon = ConfigurationManager::instance().dataTransferInfo(dringId);
+
+    auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
+    auto contactProfileId = database::getProfileId(db, infoFromDaemon.peer.toStdString());
+
+    // get the conversation if any
+    auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
+
+    if (conv.empty())
+        return;
+
+    // get interaction id from data transfer model
+    auto interactionId = dataTransferModel.getInteractionIdFromDringId(dringId);
+
+    // update information in the db
+    database::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_ONGOING);
+
+    // prepare interaction Info and emit signal for the client
+    auto conversationIdx = indexOf(conv[0]);
     if (conversationIdx != -1) {
-        auto& dataTransferUid = pimpl_->dataTransferModel.transferIdList()[interactionId];
-        if (not dataTransferUid.empty())
-            pimpl_->dataTransferModel.acceptFile(dataTransferUid, "~", 0);
+        auto& interactions = conversations[conversationIdx].interactions;
+        auto it = interactions.find(interactionId);
+        if (it != interactions.end()) {
+            it->second.status = interaction::Status::TRANSFER_ONGOING;
+            dirtyConversations = true;
+            emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
+        }
+    }
+}
+
+void
+ConversationModelPimpl::slotTransferStatusFinished(long long dringId)
+{
+    // no auto [jn] facto le code
+    DataTransferInfo infoFromDaemon = ConfigurationManager::instance().dataTransferInfo(dringId);
+
+    auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
+    auto contactProfileId = database::getProfileId(db, infoFromDaemon.peer.toStdString());
+
+    // get the conversation if any
+    auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
+
+    if (conv.empty())
+        return;
+
+    // get interaction id from data transfer model
+    auto interactionId = dataTransferModel.getInteractionIdFromDringId(dringId);
+
+    // prepare interaction Info and emit signal for the client
+    auto conversationIdx = indexOf(conv[0]);
+    if (conversationIdx != -1) {
+        auto& interactions = conversations[conversationIdx].interactions;
+        auto it = interactions.find(interactionId);
+        if (it != interactions.end()) {
+            // We need to check if current status is ONGOING as CANCELED must not be transformed into FINISHED
+            if (it->second.status == interaction::Status::TRANSFER_ONGOING) {
+                // update information in the db
+                database::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_FINISHED);
+                it->second.status = interaction::Status::TRANSFER_FINISHED;
+                dirtyConversations = true;
+                emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
+            }
+        }
+    }
+}
+
+void
+ConversationModelPimpl::slotTransferStatusError(long long dringId)
+{
+    // no auto [jn] facto le code
+    DataTransferInfo infoFromDaemon = ConfigurationManager::instance().dataTransferInfo(dringId);
+
+    auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
+    auto contactProfileId = database::getProfileId(db, infoFromDaemon.peer.toStdString());
+
+    // get the conversation if any
+    auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
+
+    if (conv.empty())
+        return;
+
+    // get interaction id from data transfer model
+    auto interactionId = dataTransferModel.getInteractionIdFromDringId(dringId);
+
+    // update information in the db
+    database::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_ERROR);
+
+    // prepare interaction Info and emit signal for the client
+    auto conversationIdx = indexOf(conv[0]);
+    if (conversationIdx != -1) {
+        auto& interactions = conversations[conversationIdx].interactions;
+        auto it = interactions.find(interactionId);
+        if (it != interactions.end()) {
+            dirtyConversations = true;
+            emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
+        }
     }
 }
 
diff --git a/src/datatransfermodel.cpp b/src/datatransfermodel.cpp
index 82d4f1d229ea8108c28a2c2852fe67264166eb77..3bc088f6922632cd0abf30da397df5b8733d04e2 100644
--- a/src/datatransfermodel.cpp
+++ b/src/datatransfermodel.cpp
@@ -65,16 +65,13 @@ public:
          Database& database,
          const CallbacksHandler& callbacksHandler);
 
+    std::vector<std::string> transferIdList() const;
+
     DataTransferModel& upLink;
-    std::map<DRing::DataTransferId, std::string> dring2lrcIdMap;
-    std::map<std::string, DRing::DataTransferId> lrc2dringIdMap; // stricly the reverse map of dring2lrcIdMap
+    std::map<long long, int> dring2lrcIdMap;
+    std::map<int, long long> lrc2dringIdMap; // stricly the reverse map of dring2lrcIdMap
     Database& database;
     const CallbacksHandler& callbacksHandler;
-
-    std::string registerTransferId(DRing::DataTransferId id);
-
-public Q_SLOTS:
-    void slotDataTransferEvent(long long dring_id, uint code);
 };
 
 DataTransferModel::Impl::Impl(DataTransferModel& up_link,
@@ -84,41 +81,18 @@ DataTransferModel::Impl::Impl(DataTransferModel& up_link,
     , callbacksHandler {callbacksHandler}
     , database {database}
     , upLink {up_link}
-{
-    connect(&callbacksHandler, &CallbacksHandler::incomingTransfer,
-            this, &DataTransferModel::Impl::slotDataTransferEvent);
-}
+{}
 
-std::string
-DataTransferModel::Impl::registerTransferId(DRing::DataTransferId dring_id)
-{
-    const auto& iter = dring2lrcIdMap.find(dring_id);
-    if (iter != std::cend(dring2lrcIdMap))
-        return iter->second;
-    while (true) {
-        auto res = dring2lrcIdMap.emplace(dring_id, QUuid::createUuid().toString().toStdString());
-        if (res.second) {
-            lrc2dringIdMap.emplace(res.first->second, dring_id);
-            return res.first->second;
-        }
-    }
-}
 
 void
-DataTransferModel::Impl::slotDataTransferEvent(long long dring_id, uint code)
+DataTransferModel::registerTransferId(long long dringId, int interactionId)
 {
-    auto event = DRing::DataTransferEventCode(code);
-    if (event == DRing::DataTransferEventCode::created) {
-        auto info = static_cast<DataTransferInfo>(ConfigurationManager::instance().dataTransferInfo(dring_id));
-        if (!info.isOutgoing) {
-            emit upLink.incomingTransfer("", "", 0, 0);
-            return;
-        }
-    }
 
-    emit upLink.transferStatusChanged("", convertDataTransferEvent(event));
+    pimpl_->dring2lrcIdMap.emplace(dringId, interactionId);
+    pimpl_->lrc2dringIdMap.emplace(interactionId, dringId);
 }
 
+
 DataTransferModel::DataTransferModel(Database& database,
                                      const CallbacksHandler& callbacksHandler)
     : QObject()
@@ -128,21 +102,21 @@ DataTransferModel::DataTransferModel(Database& database,
 DataTransferModel::~DataTransferModel() = default;
 
 std::vector<std::string>
-DataTransferModel::transferIdList() const
+DataTransferModel::Impl::transferIdList() const
 {
     VectorULongLong dring_list = ConfigurationManager::instance().dataTransferList();
-    for (auto dring_id : dring_list) {
-         pimpl_->registerTransferId(dring_id);
-    }
+    //~ for (auto dring_id : dring_list) {
+         //~ pimpl_->registerTransferId(dring_id);
+    //~ }
     std::vector<std::string> result;
-    result.reserve(dring_list.size());
-    for (auto& item : pimpl_->lrc2dringIdMap) {
-        result.push_back(item.first);
-    }
+    //~ result.reserve(dring_list.size());
+    //~ for (auto& item : pimpl_->lrc2dringIdMap) {
+        //~ result.push_back(item.first);
+    //~ }
     return result;
 }
 
-std::string
+void
 DataTransferModel::sendFile(const std::string& account_id, const std::string& peer_uri,
                             const std::string& file_path, const std::string& display_name)
 {
@@ -151,49 +125,36 @@ DataTransferModel::sendFile(const std::string& account_id, const std::string& pe
                                                            QString::fromStdString(peer_uri),
                                                            QString::fromStdString(file_path),
                                                            QString::fromStdString(display_name)));
-    return pimpl_->registerTransferId(dring_id);
-}
-
-datatransfer::Info
-DataTransferModel::transferInfo(const std::string& lrc_id)
-{
-    auto dring_id = pimpl_->lrc2dringIdMap.at(lrc_id);
-    auto dring_info = static_cast<DataTransferInfo>(ConfigurationManager::instance().dataTransferInfo(dring_id));
-    datatransfer::Info lrc_info;
-    lrc_info.uid = lrc_id;
-    lrc_info.isOutgoing = dring_info.isOutgoing;
-    lrc_info.totalSize = dring_info.totalSize;
-    lrc_info.progress = dring_info.lastEvent;
-    lrc_info.path = dring_info.displayName.toStdString();
-    lrc_info.displayName = dring_info.displayName.toStdString();
-    lrc_info.status = convertDataTransferEvent(DRing::DataTransferEventCode(dring_info.lastEvent));
-    lrc_info.accountId = dring_info.accountId.toStdString();
-    lrc_info.peerUri = dring_info.peer.toStdString();
-    return lrc_info;
 }
 
 std::streamsize
-DataTransferModel::bytesProgress(const std::string& lrc_id)
+DataTransferModel::bytesProgress(int interactionId)
 {
-    return ConfigurationManager::instance().dataTransferBytesProgress(pimpl_->lrc2dringIdMap.at(lrc_id));
+    return ConfigurationManager::instance().dataTransferBytesProgress(pimpl_->lrc2dringIdMap.at(interactionId));
 }
 
 void
-DataTransferModel::acceptFile(const std::string& lrc_id,
+DataTransferModel::accept(int interactionId,
                                       const std::string& file_path,
                                       std::size_t offset)
 {
-    auto dring_id = pimpl_->lrc2dringIdMap.at(lrc_id);
+    auto dring_id = pimpl_->lrc2dringIdMap.at(interactionId);
     ConfigurationManager::instance().acceptFileTransfer(dring_id, QString::fromStdString(file_path), offset);
 }
 
 void
-DataTransferModel::cancel(const std::string& lrc_id)
+DataTransferModel::cancel(int interactionId)
 {
-    auto dring_id = pimpl_->lrc2dringIdMap.at(lrc_id);
+    auto dring_id = pimpl_->lrc2dringIdMap.at(interactionId);
     ConfigurationManager::instance().cancelDataTransfer(dring_id);
 }
 
+int
+DataTransferModel::getInteractionIdFromDringId(long long dringId)
+{
+    return pimpl_->dring2lrcIdMap.at(dringId);
+}
+
 }} // namespace lrc::api
 
 #include "api/moc_datatransfermodel.cpp"