diff --git a/include/linphone/api/c-friend.h b/include/linphone/api/c-friend.h
index 4eea43a5e8f66541ab5a4783cb5a4f73f0fe0ac7..5de27a53015f96a50e2c5accf81a1e636772ad36 100644
--- a/include/linphone/api/c-friend.h
+++ b/include/linphone/api/c-friend.h
@@ -161,7 +161,7 @@ LINPHONE_PUBLIC void linphone_friend_remove_phone_number_with_label(LinphoneFrie
                                                                     const LinphoneFriendPhoneNumber *phone_number);
 
 /**
- * Set the display name for this friend
+ * Sets the display name for this friend
  * @param linphone_friend #LinphoneFriend object @notnil
  * @param name the display name to set @maybenil
  * @return 0 if successful, -1 otherwise
@@ -169,12 +169,42 @@ LINPHONE_PUBLIC void linphone_friend_remove_phone_number_with_label(LinphoneFrie
 LINPHONE_PUBLIC LinphoneStatus linphone_friend_set_name(LinphoneFriend *linphone_friend, const char *name);
 
 /**
- * Get the display name for this friend
+ * Sets the last name for this friend if vCard is available
+ * @param linphone_friend #LinphoneFriend object @notnil
+ * @param last_name the last name to set @maybenil
+ * @return 0 if successful, -1 otherwise
+ */
+LINPHONE_PUBLIC LinphoneStatus linphone_friend_set_last_name(LinphoneFriend *linphone_friend, const char *last_name);
+
+/**
+ * Sets the first name for this friend is available
+ * @param linphone_friend #LinphoneFriend object @notnil
+ * @param first_name the first name to set @maybenil
+ * @return 0 if successful, -1 otherwise
+ */
+LINPHONE_PUBLIC LinphoneStatus linphone_friend_set_first_name(LinphoneFriend *linphone_friend, const char *first_name);
+
+/**
+ * Gets the display name for this friend
  * @param linphone_friend #LinphoneFriend object @notnil
  * @return The display name of this friend. @maybenil
  */
 LINPHONE_PUBLIC const char *linphone_friend_get_name(const LinphoneFriend *linphone_friend);
 
+/**
+ * Gets the last name for this friend if vCard exists
+ * @param linphone_friend #LinphoneFriend object @notnil
+ * @return The last name of this friend. @maybenil
+ */
+LINPHONE_PUBLIC const char *linphone_friend_get_last_name(const LinphoneFriend *linphone_friend);
+
+/**
+ * Gets the first name for this friend if vCard exists
+ * @param linphone_friend #LinphoneFriend object @notnil
+ * @return The first name of this friend. @maybenil
+ */
+LINPHONE_PUBLIC const char *linphone_friend_get_first_name(const LinphoneFriend *linphone_friend);
+
 /**
  * get subscription flag value
  * @param linphone_friend #LinphoneFriend object @notnil
@@ -357,6 +387,13 @@ LINPHONE_PUBLIC LinphoneCore *linphone_friend_get_core(const LinphoneFriend *lin
  */
 LINPHONE_PUBLIC LinphoneVcard *linphone_friend_get_vcard(const LinphoneFriend *linphone_friend);
 
+/**
+ * Returns the a string matching the vCard inside the friend, if any
+ * @param linphone_friend #LinphoneFriend object @notnil
+ * @return the vCard as a string or NULL. @maybenil
+ */
+LINPHONE_PUBLIC const char *linphone_friend_dump_vcard(const LinphoneFriend *linphone_friend);
+
 /**
  * Binds a vCard object to a friend
  * @param linphone_friend #LinphoneFriend object @notnil
diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h
index b7668e2219682d9ffe68b38f59dc79e250ff475f..e2916d635bb057f80fe3eb7c65e7b1bfc6a01b89 100644
--- a/include/linphone/utils/utils.h
+++ b/include/linphone/utils/utils.h
@@ -140,6 +140,7 @@ inline std::string join(const std::vector<T> &elems, const S &delim) {
 }
 LINPHONE_PUBLIC std::string trim(const std::string &str);
 LINPHONE_PUBLIC std::string normalizeFilename(const std::string &str);
+LINPHONE_PUBLIC std::string flattenPhoneNumber(const std::string &str);
 
 template <typename T>
 inline const T &getEmptyConstRefObject() {
diff --git a/src/c-wrapper/api/c-account.cpp b/src/c-wrapper/api/c-account.cpp
index 99769b8a161fc8d53363307c3efea373d33b3993..97f2c7de244ab1642af9771c8533f94fe65644ad 100644
--- a/src/c-wrapper/api/c-account.cpp
+++ b/src/c-wrapper/api/c-account.cpp
@@ -329,23 +329,6 @@ bool_t linphone_account_is_phone_number(const LinphoneAccount *account, const ch
 	return TRUE;
 }
 
-static char *linphone_account_flatten_phone_number(const char *number) {
-	char *unescaped_phone_number = belle_sip_username_unescape_unnecessary_characters(number);
-	char *result = reinterpret_cast<char *>(ms_malloc0(strlen(unescaped_phone_number) + 1));
-	char *w = result;
-	const char *r;
-
-	for (r = unescaped_phone_number; *r != '\0'; ++r) {
-		if (*r == '+' || isdigit(*r)) {
-			*w++ = *r;
-		}
-	}
-
-	*w++ = '\0';
-	belle_sip_free(unescaped_phone_number);
-	return result;
-}
-
 char *linphone_account_normalize_phone_number(const LinphoneAccount *account, const char *username) {
 	AccountLogContextualizer logContextualizer(account);
 
@@ -368,7 +351,7 @@ char *linphone_account_normalize_phone_number(const LinphoneAccount *account, co
 		linphone_account_params_unref(accountParams);
 	}
 
-	char *flatten = linphone_account_flatten_phone_number(username);
+	char *flatten = ms_strdup(Utils::flattenPhoneNumber(username).c_str());
 	lDebug() << "Flattened number is [" << flatten << "] for [" << username << "]";
 
 	// if local short number, do not add international prefix
diff --git a/src/c-wrapper/api/c-friend.cpp b/src/c-wrapper/api/c-friend.cpp
index dce4d693be45d703a3a9a051f7b804d4d33a4e45..a534f8d8993a043df674f72599bbb99d52ad2804 100644
--- a/src/c-wrapper/api/c-friend.cpp
+++ b/src/c-wrapper/api/c-friend.cpp
@@ -171,6 +171,18 @@ const char *linphone_friend_get_name(const LinphoneFriend *lf) {
 	return L_STRING_TO_C(Friend::toCpp(lf)->getName());
 }
 
+const char *linphone_friend_get_last_name(const LinphoneFriend *lf) {
+	if (!lf) return NULL;
+	const std::shared_ptr<Vcard> vcard = Friend::toCpp(lf)->getVcard();
+	return vcard ? L_STRING_TO_C(vcard->getFamilyName()) : NULL;
+}
+
+const char *linphone_friend_get_first_name(const LinphoneFriend *lf) {
+	if (!lf) return NULL;
+	const std::shared_ptr<Vcard> vcard = Friend::toCpp(lf)->getVcard();
+	return vcard ? L_STRING_TO_C(vcard->getGivenName()) : NULL;
+}
+
 const char *linphone_friend_get_native_uri(const LinphoneFriend *lf) {
 	if (!lf) return NULL;
 	return L_STRING_TO_C(Friend::toCpp(lf)->getNativeUri());
@@ -241,6 +253,12 @@ LinphoneVcard *linphone_friend_get_vcard(const LinphoneFriend *lf) {
 	return vcard ? vcard->toC() : nullptr;
 }
 
+const char *linphone_friend_dump_vcard(const LinphoneFriend *lf) {
+	if (!lf) return NULL;
+	const std::shared_ptr<Vcard> vcard = Friend::toCpp(lf)->getVcard();
+	return vcard ? L_STRING_TO_C(vcard->asVcard4String()) : NULL;
+}
+
 bool_t linphone_friend_has_capability(const LinphoneFriend *lf, const LinphoneFriendCapability capability) {
 	return Friend::toCpp(lf)->hasCapability(capability);
 }
@@ -328,6 +346,24 @@ LinphoneStatus linphone_friend_set_name(LinphoneFriend *lf, const char *name) {
 	return Friend::toCpp(lf)->setName(L_C_TO_STRING(name));
 }
 
+LinphoneStatus linphone_friend_set_last_name(LinphoneFriend *lf, const char *last_name) {
+	const std::shared_ptr<Vcard> vcard = Friend::toCpp(lf)->getVcard();
+	if (vcard) {
+		vcard->setFamilyName(L_C_TO_STRING(last_name));
+		return 0;
+	}
+	return -1;
+}
+
+LinphoneStatus linphone_friend_set_first_name(LinphoneFriend *lf, const char *first_name) {
+	const std::shared_ptr<Vcard> vcard = Friend::toCpp(lf)->getVcard();
+	if (vcard) {
+		vcard->setGivenName(L_C_TO_STRING(first_name));
+		return 0;
+	}
+	return -1;
+}
+
 void linphone_friend_set_native_uri(LinphoneFriend *lf, const char *native_uri) {
 	if (!lf) return;
 	Friend::toCpp(lf)->setNativeUri(L_C_TO_STRING(native_uri));
diff --git a/src/friend/friend.cpp b/src/friend/friend.cpp
index 0871b300e434b1268c91c189ed4818a7959cd8a5..948097602377c4045b6443aef2686fa7e497b5da 100644
--- a/src/friend/friend.cpp
+++ b/src/friend/friend.cpp
@@ -548,9 +548,10 @@ void Friend::addAddress(const std::shared_ptr<const Address> &address) {
 
 void Friend::addPhoneNumber(const std::string &phoneNumber) {
 	if (phoneNumber.empty()) return;
+	auto flattenedPhoneNumber = Utils::flattenPhoneNumber(phoneNumber);
 
 	for (auto existing : getPhoneNumbers()) {
-		if (existing == phoneNumber) {
+		if (flattenedPhoneNumber == Utils::flattenPhoneNumber(existing)) {
 			lInfo() << "Trying to add an already existing phone number to friend, skipping";
 			return;
 		}
@@ -570,10 +571,12 @@ void Friend::addPhoneNumberWithLabel(const std::shared_ptr<const FriendPhoneNumb
 	if (!phoneNumber) return;
 	const std::string &phone = phoneNumber->getPhoneNumber();
 	if (phone.empty()) return;
+	auto flattenedPhoneNumber = Utils::flattenPhoneNumber(phone);
 
 	const std::string &label = phoneNumber->getLabel();
 	for (auto &existing : getPhoneNumbersWithLabel()) {
-		if (existing->getPhoneNumber() == phone && existing->getLabel() == label) {
+		if (existing->getLabel() == label &&
+		    flattenedPhoneNumber == Utils::flattenPhoneNumber(existing->getPhoneNumber())) {
 			lInfo() << "Trying to add an already existing phone number / label to friend, skipping";
 			return;
 		}
diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp
index b9c30d268584cf2256ed3166ea2b48ea94dc7b1d..f296bb65a9d5d75982f9e786da78e2e1aad1b619 100644
--- a/src/utils/utils.cpp
+++ b/src/utils/utils.cpp
@@ -228,6 +228,22 @@ string Utils::trim(const string &str) {
 	return (itBack <= itFront ? string() : string(itFront, itBack));
 }
 
+std::string Utils::flattenPhoneNumber(const std::string &str) {
+	std::string result;
+	const char *number = str.c_str();
+	char *unescaped_phone_number = belle_sip_username_unescape_unnecessary_characters(number);
+	const char *r;
+
+	for (r = unescaped_phone_number; *r != '\0'; ++r) {
+		if (*r == '+' || isdigit(*r)) {
+			result += *r;
+		}
+	}
+
+	belle_sip_free(unescaped_phone_number);
+	return result;
+}
+
 std::string Utils::normalizeFilename(const std::string &str) {
 	std::string result(str);
 #ifdef _WIN32