diff --git a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java
index 729ba671097e9530ed33b85d86a5207a8c7aac62..15fb7e524bd529f40f840e881bfc6d4cdafb30f4 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java
@@ -1,25 +1,26 @@
 /*
-* Copyright (C) 2020 by Savoir-faire Linux
-* Authors: William Enright <william.enright@savoirfairelinux.com>
-*          Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com>
-*          Johnny Flores <johnny.flores@savoirfairelinux.com>
-*          Mohammed Raza <mohammed.raza@savoirfairelinux.com>
-*          Felix Sidokhine <felix.sidokhine@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, see <https://www.gnu.org/licenses/>.
-*/
+ * Copyright (C) 2020 by Savoir-faire Linux
+ * Authors: William Enright <william.enright@savoirfairelinux.com>
+ *          Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com>
+ *          Johnny Flores <johnny.flores@savoirfairelinux.com>
+ *          Mohammed Raza <mohammed.raza@savoirfairelinux.com>
+ *          Felix Sidokhine <felix.sidokhine@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, see <https://www.gnu.org/licenses/>.
+ */
+
 package net.jami.datastore.dao;
 
 import lombok.extern.slf4j.Slf4j;
@@ -29,6 +30,7 @@ import net.jami.jams.common.objects.contacts.Contact;
 
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.util.List;
 
 @Slf4j
 public class ContactDao extends AbstractDao<Contact> {
@@ -41,35 +43,57 @@ public class ContactDao extends AbstractDao<Contact> {
             String createTable = "CREATE TABLE contacts (" +
                 "owner varchar(255), " +
                 "uri varchar(255)," +
-                "displayName varchar(255),"+
+                "displayName varchar(255)," +
+                "`timestamp` bigint," +
+                "status int," +
                 "PRIMARY KEY (owner,uri))";
             PreparedStatement ps = connection.getConnection().prepareStatement(createTable);
             ps.execute();
-        }
-        catch (SQLException e){
+        } catch (SQLException e) {
             log.error("Could not create the contacts table with error " + e.getMessage());
-        }
-        finally {
+        } finally {
             DataStore.connectionPool.returnConnection(connection);
         }
     }
 
+    //Not used because the strategy here is different.
     @Override
     public boolean storeObject(Contact object) {
         SQLConnection connection = DataStore.connectionPool.getConnection();
-        try{
-            PreparedStatement ps = connection.getConnection().prepareStatement("INSERT INTO contacts " +
-                "(owner, uri, displayName) " +
-                "VALUES " +
-                "(?, ?, ?)");
-            ps = object.getInsert(ps);
-            return ps.executeUpdate() != 0;
-        }
-        catch (Exception e){
-            log.error("An error has occurred while trying to store a user: " + e.toString());
+        try {
+            String insert = "INSERT INTO contacts (owner, uri, displayName, `timestamp`, status) VALUES " +
+                "(?, ?, ?, ?, ?)";
+            PreparedStatement ps = connection.getConnection().prepareStatement(insert);
+            object.getInsert(ps);
+            ps.executeQuery();
+            return true;
+        } catch (Exception e) {
+            log.error("Could not update contacts!");
             return false;
+        } finally {
+            DataStore.connectionPool.returnConnection(connection);
         }
-        finally {
+    }
+
+    public boolean storeContactList(List<Contact> contactList) {
+        SQLConnection connection = DataStore.connectionPool.getConnection();
+        try {
+            String delete = "DELETE FROM contacts WHERE owner = ?";
+            PreparedStatement ps = connection.getConnection().prepareStatement(delete);
+            ps.setString(1, contactList.get(0).getOwner());
+            ps.executeQuery();
+            String insert = "INSERT INTO contacts (owner, uri, displayName, `timestamp`, status) VALUES " +
+                "(?, ?, ?, ?, ?)";
+            for (Contact contact : contactList) {
+                ps = connection.getConnection().prepareStatement(insert);
+                contact.getInsert(ps);
+                ps.executeQuery();
+            }
+            return true;
+        } catch (Exception e) {
+            log.error("Could not update contacts!");
+            return false;
+        } finally {
             DataStore.connectionPool.returnConnection(connection);
         }
     }
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/contacts/Contact.java b/jams-common/src/main/java/net/jami/jams/common/objects/contacts/Contact.java
index dfcf11b391b0b0dcc43ead99a63f88183f40affa..04da47e1231be91a5b1fb99a778aea0930ff7053 100644
--- a/jams-common/src/main/java/net/jami/jams/common/objects/contacts/Contact.java
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/contacts/Contact.java
@@ -1,28 +1,30 @@
 /*
-* Copyright (C) 2020 by Savoir-faire Linux
-* Authors: William Enright <william.enright@savoirfairelinux.com>
-*          Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com>
-*          Johnny Flores <johnny.flores@savoirfairelinux.com>
-*          Mohammed Raza <mohammed.raza@savoirfairelinux.com>
-*          Felix Sidokhine <felix.sidokhine@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, see <https://www.gnu.org/licenses/>.
-*/
+ * Copyright (C) 2020 by Savoir-faire Linux
+ * Authors: William Enright <william.enright@savoirfairelinux.com>
+ *          Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com>
+ *          Johnny Flores <johnny.flores@savoirfairelinux.com>
+ *          Mohammed Raza <mohammed.raza@savoirfairelinux.com>
+ *          Felix Sidokhine <felix.sidokhine@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, see <https://www.gnu.org/licenses/>.
+ */
+
 package net.jami.jams.common.objects.contacts;
 
 import com.jsoniter.annotation.JsonIgnore;
+import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
@@ -34,24 +36,32 @@ import java.sql.ResultSet;
 @Getter
 @Setter
 @NoArgsConstructor
+@EqualsAndHashCode
 public class Contact implements DatabaseObject {
 
     @JsonIgnore //Ignore the owner because he is irrelevant.
     private String owner;
     private String uri;
     private String displayName;
+    private Long timestamp;
+    private Character status; //A = added, D = deleted.
 
     public Contact(ResultSet rs) throws Exception {
         this.owner = rs.getString("owner");
         this.uri = rs.getString("uri");
         this.displayName = rs.getString("displayName");
+        this.timestamp = rs.getLong("timestamp");
+        this.status = (char) rs.getInt("status");
     }
 
     @Override
     public PreparedStatement getInsert(PreparedStatement ps) throws Exception {
-        ps.setString(1,owner);
-        ps.setString(2,uri);
-        ps.setString(3,displayName);
+        ps.setString(1, owner);
+        ps.setString(2, uri);
+        if(displayName != null) ps.setString(3, displayName);
+        else ps.setString(3, "");
+        ps.setLong(4,timestamp);
+        ps.setInt(5,status);
         return ps;
     }
 
diff --git a/jams-common/src/main/java/net/jami/jams/common/serialization/JsoniterRegistry.java b/jams-common/src/main/java/net/jami/jams/common/serialization/JsoniterRegistry.java
index 46c0bb828afc0f185c464ed887a4086a5e2670e4..f3191945f184447ce051aa678db7356ac02e8a0e 100644
--- a/jams-common/src/main/java/net/jami/jams/common/serialization/JsoniterRegistry.java
+++ b/jams-common/src/main/java/net/jami/jams/common/serialization/JsoniterRegistry.java
@@ -27,11 +27,13 @@ import com.jsoniter.output.EncodingMode;
 import com.jsoniter.output.JsonStream;
 import com.jsoniter.spi.DecodingMode;
 import com.jsoniter.spi.JsoniterSpi;
+import net.jami.jams.common.objects.contacts.Contact;
 import net.jami.jams.common.serialization.decoders.CSRDecoder;
 import net.jami.jams.common.serialization.decoders.PrivateKeyDecoder;
 import net.jami.jams.common.serialization.decoders.X509CertificateDecoder;
 import net.jami.jams.common.serialization.encoders.PrivateKeyEncoder;
 import net.jami.jams.common.serialization.encoders.X509CertificateEncoder;
+import net.jami.jams.common.serialization.serializers.ContactCodec;
 import org.bouncycastle.pkcs.PKCS10CertificationRequest;
 
 import java.security.PrivateKey;
@@ -47,6 +49,8 @@ public class JsoniterRegistry {
         JsoniterSpi.registerTypeEncoder(X509Certificate.class,new X509CertificateEncoder());
         JsoniterSpi.registerTypeEncoder(PrivateKey.class,new PrivateKeyEncoder());
         JsoniterSpi.registerTypeDecoder(PKCS10CertificationRequest.class,new CSRDecoder());
+        JsoniterSpi.registerTypeEncoder(Contact.class,new ContactCodec());
+        JsoniterSpi.registerTypeDecoder(Contact.class,new ContactCodec());
     }
 
 
diff --git a/jams-common/src/main/java/net/jami/jams/common/serialization/serializers/ContactCodec.java b/jams-common/src/main/java/net/jami/jams/common/serialization/serializers/ContactCodec.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2ee78972523e70dec65c498f24e218a7d7aa46a
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/serialization/serializers/ContactCodec.java
@@ -0,0 +1,42 @@
+package net.jami.jams.common.serialization.serializers;
+
+import com.jsoniter.JsonIterator;
+import com.jsoniter.any.Any;
+import com.jsoniter.output.JsonStream;
+import com.jsoniter.spi.Decoder;
+import com.jsoniter.spi.Encoder;
+import net.jami.jams.common.objects.contacts.Contact;
+
+import java.io.IOException;
+
+public class ContactCodec implements Encoder, Decoder {
+
+    @Override
+    public Object decode(JsonIterator jsonIterator) throws IOException {
+        Any input = jsonIterator.readAny();
+        Contact contact = new Contact();
+        contact.setUri(input.get("uri").toString());
+        if(!input.get("added").toString().isBlank()){
+            contact.setStatus('A');
+            contact.setTimestamp(input.get("added").toLong());
+        }
+        else{
+            contact.setStatus('D');
+            contact.setTimestamp(input.get("removed").toLong());
+        }
+        return contact;
+    }
+
+    @Override
+    public void encode(Object o, JsonStream jsonStream) throws IOException {
+        Contact ct = (Contact) o;
+        StringBuilder sb = new StringBuilder();
+        sb.append("{\"uri\":\"").append(ct.getUri()).append("\",");
+        switch (ct.getStatus()){
+            case 'A': sb.append("\"added\":").append(ct.getTimestamp()); break;
+            case 'D': sb.append("\"removed\":").append(ct.getTimestamp()); break;
+        }
+        sb.append("}");
+        jsonStream.write(sb.toString().getBytes());
+    }
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/utils/ContactMerger.java b/jams-common/src/main/java/net/jami/jams/common/utils/ContactMerger.java
new file mode 100644
index 0000000000000000000000000000000000000000..f73f276cf6e4dd1db441dc4674c3820de4556082
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/utils/ContactMerger.java
@@ -0,0 +1,38 @@
+package net.jami.jams.common.utils;
+
+import net.jami.jams.common.objects.contacts.Contact;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
+public class ContactMerger {
+
+    public static List<Contact> mergeContacts(List<Contact> remote, List<Contact> local){
+        //uri - [remote,local]
+        List<Contact> output = new ArrayList<>();
+        final HashMap<String,Contact[]> contactMap = new HashMap<>();
+        remote.sort(Comparator.comparingLong(Contact::getTimestamp));
+        remote.forEach(contact -> {
+            contactMap.putIfAbsent(contact.getUri(),new Contact[]{null,null});
+            contactMap.get(contact.getUri())[0] = contact;
+        });
+        local.forEach(contact -> {
+            contactMap.putIfAbsent(contact.getUri(),new Contact[]{null,null});
+            contactMap.get(contact.getUri())[1] = contact;
+        });
+        contactMap.forEach((k,v) -> {
+            if(v[0] == null) output.add(v[1]);
+            else if(v[1] == null) output.add(v[0]);
+            else {
+                //Compare by date an choose the proper one
+                if(v[0].getTimestamp() > v[1].getTimestamp()) output.add(v[0]);
+                else output.add(v[1]);
+            }
+        });
+        return output;
+    }
+
+
+}
diff --git a/jams-common/src/test/java/net/jami/jams/common/objects/contacts/ContactTest.java b/jams-common/src/test/java/net/jami/jams/common/objects/contacts/ContactTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7ec4acaee20ec5c95da379087b5db1042fa718d3
--- /dev/null
+++ b/jams-common/src/test/java/net/jami/jams/common/objects/contacts/ContactTest.java
@@ -0,0 +1,76 @@
+package net.jami.jams.common.objects.contacts;
+
+import com.jsoniter.JsonIterator;
+import com.jsoniter.output.JsonStream;
+import com.jsoniter.spi.JsoniterSpi;
+import net.jami.jams.common.serialization.serializers.ContactCodec;
+import net.jami.jams.common.utils.ContactMerger;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ContactTest {
+
+    @BeforeAll
+    public static void init(){
+        JsoniterSpi.registerTypeDecoder(Contact.class,new ContactCodec());
+        JsoniterSpi.registerTypeEncoder(Contact.class,new ContactCodec());
+    }
+
+    @Test
+    public void deserialize(){
+        String str = "[{\"uri\":\"tcp://def@local\",\"added\":1594742298377},{\"uri\":\"tcp://abc@19293.com\",\"removed\":1594742298377}]";
+        Contact[] contacts = JsonIterator.deserialize(str,Contact[].class);
+        Assertions.assertEquals(2,contacts.length);
+    }
+
+    @Test
+    public void serialize(){
+        Contact contact1 = new Contact();
+        contact1.setOwner("fsidokhine");
+        contact1.setStatus('A');
+        contact1.setTimestamp(System.currentTimeMillis());
+        contact1.setUri("tcp://def@local");
+        Contact contact2 = new Contact();
+        contact2.setOwner("fsidokhine");
+        contact2.setStatus('D');
+        contact2.setTimestamp(System.currentTimeMillis());
+        contact2.setUri("tcp://abc@19293.com");
+        ArrayList<Contact> lst = new ArrayList<>();
+        lst.add(contact1);
+        lst.add(contact2);
+        String str = JsonStream.serialize(lst);
+        Assertions.assertNotNull(str);
+    }
+
+    @Test
+    public void mergeTest(){
+        Contact contact1 = new Contact();
+        contact1.setOwner("fsidokhine");
+        contact1.setStatus('A');
+        contact1.setTimestamp(System.currentTimeMillis());
+        contact1.setUri("tcp://def@local");
+        Contact contact2 = new Contact();
+        contact2.setOwner("fsidokhine");
+        contact2.setStatus('D');
+        contact2.setTimestamp(System.currentTimeMillis());
+        contact2.setUri("tcp://abc@19293.com");
+        ArrayList<Contact> lst = new ArrayList<>();
+        lst.add(contact1);
+        lst.add(contact2);
+        Contact contact3 = new Contact();
+        contact3.setOwner("fsidokhine");
+        contact3.setStatus('A');
+        contact3.setTimestamp(System.currentTimeMillis() + 10000);
+        contact3.setUri("tcp://abc@19293.com");
+        ArrayList<Contact> lst2 = new ArrayList<>();
+        lst2.add(contact3);
+        List<Contact> out = ContactMerger.mergeContacts(lst,lst2);
+        Assertions.assertEquals(2,out.size());
+    }
+}
\ No newline at end of file
diff --git a/jams-launcher/src/main/java/launcher/AppStarter.java b/jams-launcher/src/main/java/launcher/AppStarter.java
index da0e68e29528f017c185ae3b5db1a78055ecf1f5..e56560b2e1479d5bfb6a474bb56c74dea86fa8e3 100644
--- a/jams-launcher/src/main/java/launcher/AppStarter.java
+++ b/jams-launcher/src/main/java/launcher/AppStarter.java
@@ -87,7 +87,7 @@ public class AppStarter extends Thread {
     public AppStarter(String[] args) {
         parentArgs = args;
         try {
-            jamsProcessId = startAccountManagementServer(args);
+            startAccountManagementServer(args);
             setupZmqBridge();
             Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                 log.info("Shutting down...");
@@ -108,6 +108,7 @@ public class AppStarter extends Thread {
     //and run the good old routine
     @Override
     public void run() {
+        //TODO: Hack this a bit to get it to work better - passing arguments damnit.
         while (true) {
             try {
                 if (doUpdate.get()) {
@@ -115,7 +116,7 @@ public class AppStarter extends Thread {
                     ProcessHandle.of(jamsProcessId).get().destroyForcibly();
                     // transfer newly downloaded files to the right folder.
                     doUpdate.set(false);
-                    //Unpack the update.
+                    //Upack the update.
                     unpackUpdate();
                     // Restart the main JAR and set the processId to it.
                     jamsProcessId = startAccountManagementServer(parentArgs);
@@ -133,6 +134,7 @@ public class AppStarter extends Thread {
 
     public static long startAccountManagementServer(String[] parentArgs) throws IOException {
         ProcessBuilder pb = null;
+        Process p;
         switch (parentArgs.length) {
             case 1:
                 pb = new ProcessBuilder("java", "-jar", "jams-server.jar", parentArgs[0]);
@@ -147,7 +149,7 @@ public class AppStarter extends Thread {
         assert pb != null;
         pb.directory(new File(System.getProperty("user.dir")));
         pb.inheritIO();
-        Process p = pb.start();
+        p = pb.start();
         return p.pid();
     }
 }
\ No newline at end of file
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java
index 0f176bd3461bde040455603e8d220f1eb0f56057..d521a2e7bba27d714b16b7e9c79881b90b8c84e4 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java
@@ -33,8 +33,11 @@ import net.jami.jams.common.dao.StatementElement;
 import net.jami.jams.common.dao.StatementList;
 import net.jami.jams.common.objects.contacts.Contact;
 import net.jami.jams.common.serialization.tomcat.TomcatCustomErrorHandler;
+import net.jami.jams.common.utils.ContactMerger;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import static net.jami.jams.server.Server.dataStore;
@@ -42,6 +45,7 @@ import static net.jami.jams.server.Server.dataStore;
 @WebServlet("/api/auth/contacts")
 public class ContactServlet extends HttpServlet {
 
+
     /**
      * @apiVersion 1.0.0
      * @api {get} /api/auth/contacts View contacts
@@ -52,8 +56,13 @@ public class ContactServlet extends HttpServlet {
      * @apiSuccessExample {json} Success-Response:
      *     [{
      *       "uri": "jami://7e3ab29383",
-     *       "displayName": "John Doe"
-     *     }]
+     *       "added": 18272662662
+     *     },
+     *     {
+     *        "uri": "jami://7e3ab29383",
+     *        "removed": 12387873
+     *      },
+     *     ]
      */
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
@@ -63,6 +72,7 @@ public class ContactServlet extends HttpServlet {
         resp.getOutputStream().write(JsonStream.serialize(contactList).getBytes());
     }
 
+
     /**
      * @apiVersion 1.0.0
      * @api {put} /api/auth/contacts Add a contact
@@ -72,8 +82,7 @@ public class ContactServlet extends HttpServlet {
      * @apiParam {body} Contact JSON representation of the contact object
      * @apiParamExample {json} Request-Example:
      *      {
-     *        "uri": "jami://7e3ab29383",
-     *        "displayName": "John Doe"
+     *        "uri": "jami://7e3ab29383"
      *      }
      *
      * @apiSuccess (200) {null} null successfully added contact
@@ -82,8 +91,17 @@ public class ContactServlet extends HttpServlet {
     @Override
     protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         Contact contact = JsonIterator.deserialize(req.getInputStream().readAllBytes(),Contact.class);
+        //TODO: Replace with mergetool.
+        contact.setTimestamp(System.currentTimeMillis());
+        contact.setStatus('A');
         contact.setOwner(req.getAttribute("username").toString());
-        if(dataStore.getContactDao().storeObject(contact)) resp.setStatus(200);
+        StatementList statementList = new StatementList();
+        statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),""));
+        List<Contact> localList = dataStore.getContactDao().getObjects(statementList);
+        List<Contact> remoteList = new ArrayList<>();
+        remoteList.add(contact);
+        List<Contact> result = ContactMerger.mergeContacts(localList,remoteList);
+        if(dataStore.getContactDao().storeContactList(result)) resp.setStatus(200);
         else TomcatCustomErrorHandler.sendCustomError(resp,500,"could not store a contact due to server-side error");
     }
 
@@ -103,7 +121,42 @@ public class ContactServlet extends HttpServlet {
         StatementList statementList = new StatementList();
         statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"AND"));
         statementList.addStatement(new StatementElement("uri","=",req.getParameter("uri"),""));
-        if(dataStore.getContactDao().deleteObject(statementList)) resp.setStatus(200);
+        List<Contact> remoteList = dataStore.getContactDao().getObjects(statementList);
+        remoteList.get(0).setStatus('D');
+        remoteList.get(0).setTimestamp(System.currentTimeMillis());
+        statementList = new StatementList();
+        statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"AND"));
+        List<Contact> localList = dataStore.getContactDao().getObjects(statementList);
+        List<Contact> result = ContactMerger.mergeContacts(localList,remoteList);
+        if(dataStore.getContactDao().storeContactList(result)) resp.setStatus(200);
         else TomcatCustomErrorHandler.sendCustomError(resp,500,"could not delete a contact due to server-side error");
     }
+
+
+    /**
+     * @apiVersion 1.0.0
+     * @api {post} /api/auth/contacts Add a contact
+     * @apiName putContact
+     * @apiGroup Contacts
+     *
+     * @apiParam {body} Contact JSON representation of the contact object
+     * @apiParamExample {json} Request-Example:
+     *[
+     * {"uri":"tcp://def@local","added":1594742298377},
+     * {"uri":"tcp://abc@19293.com","removed":1594742298377}
+     * ]
+     *
+     * @apiSuccess (200) {json} Contact[] successfully added contact
+     * @apiError (500) {null} null contact could not be successfully added
+     */
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        StatementList statementList = new StatementList();
+        statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),""));
+        List<Contact> localList = dataStore.getContactDao().getObjects(statementList);
+        List<Contact> remoteList = Arrays.asList(JsonIterator.deserialize(req.getInputStream().readAllBytes(),Contact[].class));
+        List<Contact> result = ContactMerger.mergeContacts(localList,remoteList);
+        if(!dataStore.getContactDao().storeContactList(result)) TomcatCustomErrorHandler.sendCustomError(resp,500,"Could not store contacts!");
+        resp.getOutputStream().write(JsonStream.serialize(result).getBytes());
+    }
 }
diff --git a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java
index e8178efa0e8d3e436db4f55a26de17d3d8c46bf5..1fe4a9d5cb105a3ccd0297bf72f784b407ad4a29 100644
--- a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java
+++ b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java
@@ -51,7 +51,7 @@ public class UserProfileService {
         UserProfile[] profiles = null;
         Connection connection = null;
         try {
-            queryString = URLEncoder.encode(queryString,StandardCharsets.UTF_8).replace("%","\\");
+            queryString = queryString.replaceAll("[^\\x00-\\x7F]","*");
             connection = connectionFactory.getConnection();
             try {
                 connection.open();
@@ -84,7 +84,7 @@ public class UserProfileService {
     public static SearchRequest buildRequest(String queryString, String field) {
 
         if (!queryString.startsWith("*"))
-            queryString = queryString.concat("*");
+            queryString = "*".concat(queryString).concat("*");
 
         if(field.equals("LOGON_NAME")) {
             return SearchRequest.builder()