diff --git a/src/api/call.h b/src/api/call.h
index 9cafe66def2916beca0bf34d072b716b28786745..496fad1ab56164ae4d3686e97659143d79760fd3 100644
--- a/src/api/call.h
+++ b/src/api/call.h
@@ -131,6 +131,7 @@ struct Info
     Status status = Status::INVALID;
     Type type = Type::INVALID;
     std::string peer;
+    bool isOutoging;
     bool audioMuted = false;
     bool videoMuted = false;
 };
diff --git a/src/api/contactmodel.h b/src/api/contactmodel.h
index 9ef26dd67851f2561b9b26740cd2423f4f3ffed0..838e14151ea595f5c89a78e15a5f97e095effdf5 100644
--- a/src/api/contactmodel.h
+++ b/src/api/contactmodel.h
@@ -113,6 +113,11 @@ Q_SIGNALS:
      * @param contactUri
      */
     void contactAdded(const std::string& contactUri) const;
+    /**
+     * Connect this signal to know when a pending contact was accepted.
+     * @param contactUri
+     */
+    void pendingContactAccepted(const std::string& contactUri) const;
     /**
      * Connect this signal to know when an account was removed.
      * @param contactUri
diff --git a/src/authority/databasehelper.cpp b/src/authority/databasehelper.cpp
index 8be410d6d21a288fb0e2be92b9eae8f849465c58..7f5da0d629459f0649b82627e38aa70877d2bc79 100644
--- a/src/authority/databasehelper.cpp
+++ b/src/authority/databasehelper.cpp
@@ -143,7 +143,7 @@ getConversationsBetween(Database& db, const std::string& accountProfile, const s
 }
 
 std::string
-beginConversationsBetween(Database& db, const std::string& accountProfile, const std::string& contactProfile)
+beginConversationsBetween(Database& db, const std::string& accountProfile, const std::string& contactProfile, const std::string& firstMessage)
 {
     // Add conversation between account and profile
     auto newConversationsId = db.select("IFNULL(MAX(id), 0) + 1",
@@ -156,17 +156,18 @@ beginConversationsBetween(Database& db, const std::string& accountProfile, const
     db.insertInto("conversations",
                   {{":id", "id"}, {":participant_id", "participant_id"}},
                   {{":id", newConversationsId}, {":participant_id", contactProfile}});
-    // Add "Conversation started" interaction
-    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", accountProfile}, {":author_id", accountProfile},
-                  {":conversation_id", newConversationsId},
-                  {":timestamp", std::to_string(std::time(nullptr))},
-                  {":body", "Conversation started"}, {":type", "CONTACT"},
-                  {":status", "SUCCEED"}});
+    // Add first interaction
+    if (!firstMessage.empty())
+        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", accountProfile}, {":author_id", accountProfile},
+                      {":conversation_id", newConversationsId},
+                      {":timestamp", std::to_string(std::time(nullptr))},
+                      {":body", firstMessage}, {":type", "CONTACT"},
+                      {":status", "SUCCEED"}});
     return newConversationsId;
 }
 
@@ -208,6 +209,41 @@ addMessageToConversation(Database& db,
                           {":status", to_string(msg.status)}});
 }
 
+int
+addOrUpdateMessage(Database& db,
+                         const std::string& accountProfile,
+                         const std::string& conversationId,
+                         const api::interaction::Info& msg,
+                         const std::string& daemonId)
+{
+    // Check if profile is already present.
+    auto msgAlreadyExists = db.select("id",
+                                      "interactions",
+                                      "daemon_id=:daemon_id",
+                                       {{":daemon_id", daemonId}});
+    if (msgAlreadyExists.payloads.empty()) {
+        return db.insertInto("interactions",
+                              {{":account_id", "account_id"}, {":author_id", "author_id"},
+                              {":conversation_id", "conversation_id"}, {":timestamp", "timestamp"},
+                              {":body", "body"}, {":type", "type"}, {":daemon_id", "daemon_id"},
+                              {":status", "status"}},
+                              {{":account_id", accountProfile}, {":author_id", msg.authorUri},
+                              {":conversation_id", conversationId},
+                              {":timestamp", std::to_string(msg.timestamp)},
+                              {":body", msg.body}, {":type", to_string(msg.type)}, {":daemon_id", daemonId},
+                              {":status", to_string(msg.status)}});
+    } else {
+        // already exists
+        db.update("interactions",
+                  "body=:body",
+                  {{":body", msg.body}},
+                  "daemon_id=:daemon_id",
+                   {{":daemon_id", daemonId}});
+        return std::stoi(msgAlreadyExists.payloads[0]);
+    }
+
+}
+
 void addDaemonMsgId(Database& db,
                     const std::string& interactionId,
                     const std::string& daemonId)
@@ -241,7 +277,7 @@ void updateInteractionStatus(Database& db, unsigned int id,
 void clearHistory(Database& db,
                   const std::string& conversationId)
 {
-    db.deleteFrom("interactions", "conversation_id=:id AND type!='CONTACT'", {{":id", conversationId}});
+    db.deleteFrom("interactions", "conversation_id=:id", {{":id", conversationId}});
 }
 
 void
diff --git a/src/authority/databasehelper.h b/src/authority/databasehelper.h
index 11999fa39663b24ee83ebfc23ab1b732a6fab6f2..34d61250077ac9a4ec4d92246b6ef1cd5d608ac0 100644
--- a/src/authority/databasehelper.h
+++ b/src/authority/databasehelper.h
@@ -103,11 +103,13 @@ std::vector<std::string> getConversationsBetween(Database& db,
  * @param db
  * @param accountProfile the id of the account in the database
  * @param contactProfile the id of the contact in the database
+ * @param firstMessage the body of the first message
  * @return conversation_id of the new conversation.
  */
 std::string beginConversationsBetween(Database& db,
                                       const std::string& accountProfile,
-                                      const std::string& contactProfile);
+                                      const std::string& contactProfile,
+                                      const std::string& firstMessage = "");
 
 /**
  * Return interactions from a conversation
@@ -129,6 +131,21 @@ int addMessageToConversation(Database& db,
                               const std::string& conversationId,
                               const api::interaction::Info& msg);
 
+/**
+* Add or update an entry into interactions linked to a conversation.
+* @param  db
+* @param  accountProfile
+* @param  conversationId
+* @param  msg
+* @param  daemonId
+* @return the id of the inserted interaction
+*/
+int addOrUpdateMessage(Database& db,
+                       const std::string& accountProfile,
+                       const std::string& conversationId,
+                       const api::interaction::Info& msg,
+                       const std::string& daemonId);
+
 /**
  * Change the daemon_id column for an interaction
  * @param db
diff --git a/src/contactmodel.cpp b/src/contactmodel.cpp
index 7ab5ffc79f159285bfc72b1bba772e3ddb53dfa3..c9230aaedba5fa853b5a33bb1cbac23e161085e9 100644
--- a/src/contactmodel.cpp
+++ b/src/contactmodel.cpp
@@ -200,6 +200,7 @@ ContactModel::addContact(contact::Info contactInfo)
         break;
     case profile::Type::PENDING:
         daemon::addContactFromPending(owner, profile.uri);
+        emit pendingContactAccepted(profile.uri);
         daemon::addContact(owner, profile.uri); // BUGS?: daemon::addContactFromPending not always add the contact
         break;
     case profile::Type::RING:
diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp
index 18b17d97a4a4005889c5ba7a8368a10b572f832f..9b16f87a9d3c45916e8865eec803073221da2ab6 100644
--- a/src/conversationmodel.cpp
+++ b/src/conversationmodel.cpp
@@ -98,7 +98,7 @@ public:
      * @param callId
      * @param body
      */
-    void addCallMessage(const std::string& callId, const std::string& body);
+    void addOrUpdateCallMessage(const std::string& callId, const std::string& body);
     /**
      * Add a new message from a peer in the database
      * @param from the peer uri
@@ -136,10 +136,15 @@ public Q_SLOTS:
      */
     void slotContactModelUpdated();
     /**
-     * Listen from contactModel when aa new contact is added
+     * Listen from contactModel when a new contact is added
      * @param uri
      */
     void slotContactAdded(const std::string& uri);
+    /**
+     * Listen from contactModel when a pending contact is accepted
+     * @param uri
+     */
+    void slotPendingContactAccepted(const std::string& uri);
     /**
      * Listen from contactModel when aa new contact is removed
      * @param uri
@@ -459,7 +464,7 @@ ConversationModel::sendMessage(const std::string& uid, const std::string& body)
 
         if (not conversation.callId.empty()
             and (owner.callModel->getCall(conversation.callId).status != call::Status::IN_PROGRESS
-                 or owner.callModel->getCall(conversation.callId).status != call::Status::PAUSED)) {
+            or owner.callModel->getCall(conversation.callId).status != call::Status::PAUSED)) {
 
             owner.callModel->sendSipMessage(conversation.callId, body);
 
@@ -605,6 +610,8 @@ ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked,
             this, &ConversationModelPimpl::slotContactModelUpdated);
     connect(&*linked.owner.contactModel, &ContactModel::contactAdded,
             this, &ConversationModelPimpl::slotContactAdded);
+    connect(&*linked.owner.contactModel, &ContactModel::pendingContactAccepted,
+            this, &ConversationModelPimpl::slotPendingContactAccepted);
     connect(&*linked.owner.contactModel, &ContactModel::contactRemoved,
             this, &ConversationModelPimpl::slotContactRemoved);
 
@@ -695,11 +702,15 @@ ConversationModelPimpl::sortConversations()
         conversations.begin(), conversations.end(),
         [](const auto& conversationA, const auto& conversationB)
         {
+            // A or B is a temporary contact
+            if (conversationA.participants.empty()) return true;
+            if (conversationB.participants.empty()) return false;
             auto historyA = conversationA.interactions;
             auto historyB = conversationB.interactions;
             // A or B is a new conversation (without CONTACT interaction)
-            if (historyA.empty()) return true;
-            if (historyB.empty()) return false;
+            if (conversationA.uid.empty() || conversationB.uid.empty()) return conversationA.uid.empty();
+            if (historyA.empty()) return false;
+            if (historyB.empty()) return true;
             // Sort by last Interaction
             try
             {
@@ -710,7 +721,7 @@ ConversationModelPimpl::sortConversations()
             catch (const std::exception& e)
             {
                 qDebug() << "ConversationModel::sortConversations(), can't get lastMessage";
-                return true;
+                return false;
             }
         });
     dirtyConversations = true;
@@ -731,7 +742,18 @@ ConversationModelPimpl::slotContactAdded(const std::string& uri)
     auto contactProfileId = database::getOrInsertProfile(db, uri);
     auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
     if (conv.empty()) {
-        conv.emplace_back(database::beginConversationsBetween(db, accountProfileId, contactProfileId));
+        std::string interaction = "";
+        try {
+            auto contact = linked.owner.contactModel->getContact(uri);
+            interaction = contact.profileInfo.type == profile::Type::PENDING ?
+                QObject::tr("Invitation received").toStdString() :
+                QObject::tr("Contact added").toStdString();
+        } catch (...) {}
+        conv.emplace_back(
+            database::beginConversationsBetween(db, accountProfileId,
+                contactProfileId, interaction
+            )
+        );
     }
     // Add the conversation if not already here
     if (indexOf(conv[0]) == -1)
@@ -746,6 +768,36 @@ ConversationModelPimpl::slotContactAdded(const std::string& uri)
     emit linked.modelSorted();
 }
 
+void
+ConversationModelPimpl::slotPendingContactAccepted(const std::string& uri)
+{
+    auto contactProfileId = database::getOrInsertProfile(db, uri);
+    auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
+    if (conv.empty()) {
+        conv.emplace_back(
+            database::beginConversationsBetween(db, accountProfileId,
+                contactProfileId, QObject::tr("Invitation accepted").toStdString()
+            )
+        );
+    } else {
+        try {
+            auto contact = linked.owner.contactModel->getContact(uri);
+            auto msg = interaction::Info {accountProfileId,
+                                          QObject::tr("Invitation accepted").toStdString(),
+                                          std::time(nullptr), interaction::Type::CONTACT,
+                                          interaction::Status::SUCCEED};
+            auto msgId = database::addMessageToConversation(db, accountProfileId, conv[0], msg);
+            auto conversationIdx = indexOf(conv[0]);
+            conversations[conversationIdx].interactions.emplace(msgId, msg);
+            dirtyConversations = true;
+            emit linked.newUnreadMessage(conv[0], msgId, msg);
+        } catch (std::out_of_range& e) {
+            qDebug() << "ConversationModelPimpl::slotContactAdded can't find contact";
+        }
+    }
+}
+
+
 void
 ConversationModelPimpl::slotContactRemoved(const std::string& uri)
 {
@@ -886,24 +938,49 @@ ConversationModelPimpl::slotCallStatusChanged(const std::string& callId)
 void
 ConversationModelPimpl::slotCallStarted(const std::string& callId)
 {
-    addCallMessage(callId, "📞 Call started");
+    try {
+        auto call = linked.owner.callModel->getCall(callId);
+        if (call.isOutoging)
+            addOrUpdateCallMessage(callId, QObject::tr("📞 Outgoing call").toStdString());
+        else
+            addOrUpdateCallMessage(callId, QObject::tr("📞 Incoming call").toStdString());
+    } catch (std::out_of_range& e) {
+        qDebug() << "ConversationModelPimpl::slotCallEnded can't end inexistant call";
+    }
 }
 
 void
 ConversationModelPimpl::slotCallEnded(const std::string& callId)
 {
-    addCallMessage(callId, "🕽 Call ended");
-
-    // reset the callId stored in the conversation
-    for (auto& conversation: conversations)
-        if (conversation.callId == callId) {
-            conversation.callId = "";
-            dirtyConversations = true;
+    try {
+        auto call = linked.owner.callModel->getCall(callId);
+        if (call.startTime.time_since_epoch().count() != 0) {
+            if (call.isOutoging)
+                addOrUpdateCallMessage(callId, QObject::tr("📞 Outgoing call - ").toStdString()
+                    + linked.owner.callModel->getFormattedCallDuration(callId));
+            else
+                addOrUpdateCallMessage(callId, QObject::tr("📞 Incoming call - ").toStdString()
+                    + linked.owner.callModel->getFormattedCallDuration(callId));
+        } else {
+            if (call.isOutoging)
+                addOrUpdateCallMessage(callId, QObject::tr("🕽 Missed outgoing call").toStdString());
+            else
+                addOrUpdateCallMessage(callId, QObject::tr("🕽 Missed incoming call").toStdString());
         }
+
+        // reset the callId stored in the conversation
+        for (auto& conversation: conversations)
+            if (conversation.callId == callId) {
+                conversation.callId = "";
+                dirtyConversations = true;
+            }
+    } catch (std::out_of_range& e) {
+        qDebug() << "ConversationModelPimpl::slotCallEnded can't end inexistant call";
+    }
 }
 
 void
-ConversationModelPimpl::addCallMessage(const std::string& callId, const std::string& body)
+ConversationModelPimpl::addOrUpdateCallMessage(const std::string& callId, const std::string& body)
 {
     // Get conversation
     for (auto& conversation: conversations) {
@@ -911,11 +988,19 @@ ConversationModelPimpl::addCallMessage(const std::string& callId, const std::str
             auto uid = conversation.uid;
             auto msg = interaction::Info {accountProfileId, body, std::time(nullptr),
                                          interaction::Type::CALL, interaction::Status::SUCCEED};
-            int msgId = database::addMessageToConversation(db, accountProfileId, conversation.uid, msg);
-            conversation.interactions.emplace(msgId, msg);
-            conversation.lastMessageUid = msgId;
+            int msgId = database::addOrUpdateMessage(db, accountProfileId, conversation.uid, msg, callId);
+            auto newInteraction = conversation.interactions.find(msgId) == conversation.interactions.end();
+            if (newInteraction) {
+                conversation.lastMessageUid = msgId;
+                conversation.interactions.emplace(msgId, msg);
+            } else {
+                conversation.interactions[msgId] = msg;
+            }
             dirtyConversations = true;
-            emit linked.newUnreadMessage(conversation.uid, msgId, msg);
+            if (newInteraction)
+                emit linked.newUnreadMessage(conversation.uid, msgId, msg);
+            else
+                emit linked.interactionStatusUpdated(conversation.uid, msgId, msg);
             sortConversations();
             emit linked.modelSorted();
         }
@@ -964,7 +1049,10 @@ ConversationModelPimpl::addIncomingMessage(const std::string& from,
     auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
     auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
     if (conv.empty()) {
-        conv.emplace_back(database::beginConversationsBetween(db, accountProfileId, contactProfileId));
+        conv.emplace_back(database::beginConversationsBetween(
+            db, accountProfileId, contactProfileId,
+            QObject::tr("Invitation received").toStdString()
+        ));
     }
     auto authorId = authorProfileId.empty()? contactProfileId: authorProfileId;
     auto msg = interaction::Info {authorId, body, std::time(nullptr),
diff --git a/src/database.cpp b/src/database.cpp
index 32654565f820bffe9f6f112857623e27b8a9466e..321e5e8cc46b8e1c5ce2ad8790151e9bad0c153e 100644
--- a/src/database.cpp
+++ b/src/database.cpp
@@ -20,6 +20,7 @@
 #include "database.h"
 
 // Qt
+#include <QObject>
 #include <QtCore/QDir>
 #include <QtCore/QDebug>
 #include <QtCore/QFile>
@@ -533,25 +534,10 @@ Database::migrateTextHistory()
 
                     // Load interactions
                     auto groupsArray = loadDoc["groups"].toArray();
-                    auto beginConversation = true;
                     for (const auto& groupObject: groupsArray) {
                         auto messagesArray = groupObject.toObject()["messages"].toArray();
                         for (const auto& messageRef: messagesArray) {
                             auto messageObject = messageRef.toObject();
-                            if (beginConversation) {
-                                // Add "Conversation started" message
-                                insertInto("interactions",
-                                            {{":account_id", "account_id"}, {":author_id", "author_id"},
-                                            {":conversation_id", "conversation_id"}, {":timestamp", "timestamp"},
-                                            {":body", "body"}, {":type", "type"},
-                                            {":status", "status"}},
-                                            {{":account_id", accountId}, {":author_id", accountId},
-                                            {":conversation_id", newConversationsId},
-                                            {":timestamp", std::to_string(messageObject["timestamp"].toInt())},
-                                            {":body", "Conversation started"}, {":type", "CONTACT"},
-                                            {":status", "SUCCEED"}});
-                                beginConversation = false;
-                            }
                             auto direction = messageObject["direction"].toInt();
                             auto body = messageObject["payloads"].toArray()[0].toObject()["payload"].toString();
                             insertInto("interactions",
diff --git a/src/newcallmodel.cpp b/src/newcallmodel.cpp
index 3d1a0fb235d35d02f713698eafa92d86115c31f1..506b3191593827a2789f596f94d7ce79093bb0fc 100644
--- a/src/newcallmodel.cpp
+++ b/src/newcallmodel.cpp
@@ -138,6 +138,7 @@ NewCallModel::createCall(const std::string& url)
     auto callInfo = std::make_shared<call::Info>();
     callInfo->id = callId.toStdString();
     callInfo->peer = url;
+    callInfo->isOutoging = true;
     callInfo->status =  call::Status::SEARCHING;
     callInfo->type =  call::Type::DIALOG;
     pimpl_->calls.emplace(callId.toStdString(), std::move(callInfo));
@@ -231,18 +232,23 @@ NewCallModel::togglePause(const std::string& callId) const
 void
 NewCallModel::toggleMedia(const std::string& callId, const NewCallModel::Media media, bool flag) const
 {
+    auto it = pimpl_->calls.find(callId);
+    if (it == pimpl_->calls.end()) return;
+    auto& call = it->second;
     switch(media)
     {
     case NewCallModel::Media::AUDIO:
         CallManager::instance().muteLocalMedia(callId.c_str(),
                                                DRing::Media::Details::MEDIA_TYPE_AUDIO,
                                                flag);
+        call->audioMuted = flag;
         break;
 
     case NewCallModel::Media::VIDEO:
         CallManager::instance().muteLocalMedia(callId.c_str(),
                                                DRing::Media::Details::MEDIA_TYPE_VIDEO,
                                                flag);
+        call->videoMuted = flag;
         break;
 
     case NewCallModel::Media::NONE:
@@ -359,6 +365,7 @@ NewCallModelPimpl::slotIncomingCall(const std::string& accountId, const std::str
     auto callInfo = std::make_shared<call::Info>();
     callInfo->id = callId;
     callInfo->peer = fromId;
+    callInfo->isOutoging = false;
     callInfo->status =  call::Status::INCOMING_RINGING;
     callInfo->type =  call::Type::DIALOG;
     calls.emplace(callId, std::move(callInfo));
@@ -378,9 +385,7 @@ NewCallModelPimpl::slotCallStateChanged(const std::string& callId, const std::st
         } else if (state == "HUNGUP") {
             calls[callId]->status = call::Status::TERMINATING;
         } else if (state == "FAILURE" || state == "OVER") {
-            if (calls[callId]->startTime.time_since_epoch().count() != 0) {
-                emit linked.callEnded(callId);
-            }
+            emit linked.callEnded(callId);
             calls[callId]->status = call::Status::ENDED;
         } else if (state == "INACTIVE") {
             calls[callId]->status = call::Status::INACTIVE;
diff --git a/test/conversationmodeltester.cpp b/test/conversationmodeltester.cpp
index 0baec70c47fadb6a5c4e7fdee39fb06db9ac6283..78356dfeaf620b1e17e48eda247257811e7b3857 100644
--- a/test/conversationmodeltester.cpp
+++ b/test/conversationmodeltester.cpp
@@ -170,8 +170,8 @@ ConversationModelTester::testSendMessageAndClearHistory()
         for (const auto& conversation: conversations) {
         if (conversation.uid == firstConversation) {
             conversationExists = true;
-            // Should contains "Conversation started" + "Hello World!"
-            CPPUNIT_ASSERT_EQUAL((int)conversation.interactions.size(), 2);
+            // Should contains "Hello World!"
+            CPPUNIT_ASSERT_EQUAL((int)conversation.interactions.size(), 1);
             CPPUNIT_ASSERT_EQUAL((*conversation.interactions.rbegin()).second.body, std::string("Hello World!"));
             break;
         }
@@ -187,8 +187,7 @@ ConversationModelTester::testSendMessageAndClearHistory()
     for (const auto& conversation: conversations) {
         if (conversation.uid == firstConversation) {
             conversationExists = true;
-            // contains the "Conversation started" message.
-            CPPUNIT_ASSERT_EQUAL((int)conversation.interactions.size(), 1);
+            CPPUNIT_ASSERT_EQUAL((int)conversation.interactions.size(), 0);
             break;
         }
     }
@@ -205,7 +204,7 @@ ConversationModelTester::testReceiveMessageAndSetRead()
     QMap<QString, QString> payloads;
     payloads["text/plain"] = "This is not a message";
     ConfigurationManager::instance().emitIncomingAccountMessage(accInfo_.id.c_str(),
-    firstConversation.participants.front().c_str(), payloads);
+        firstConversation.participants.front().c_str(), payloads);
     auto unreadMessage = WaitForSignalHelper(*accInfo_.conversationModel,
         SIGNAL(newUnreadMessage(const std::string&, uint64_t, const interaction::Info&))).wait(1000);
     CPPUNIT_ASSERT_EQUAL(unreadMessage, true);